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_message.c
ADDED
@@ -0,0 +1,671 @@
|
|
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
|
+
#include "decode_rfh.h"
|
19
|
+
|
20
|
+
/* --------------------------------------------------
|
21
|
+
* Initialize Ruby ID's for Message Class
|
22
|
+
*
|
23
|
+
* This function is called when the library is loaded
|
24
|
+
* by ruby
|
25
|
+
* --------------------------------------------------*/
|
26
|
+
|
27
|
+
static ID ID_data;
|
28
|
+
static ID ID_message;
|
29
|
+
static ID ID_descriptor;
|
30
|
+
static ID ID_headers;
|
31
|
+
static ID ID_data_set;
|
32
|
+
static ID ID_size;
|
33
|
+
static ID ID_name_value;
|
34
|
+
static ID ID_xml;
|
35
|
+
static ID ID_gsub;
|
36
|
+
static ID ID_header_type;
|
37
|
+
|
38
|
+
void Message_id_init()
|
39
|
+
{
|
40
|
+
ID_data = rb_intern("data");
|
41
|
+
ID_size = rb_intern("size");
|
42
|
+
ID_data_set = rb_intern("data=");
|
43
|
+
ID_descriptor = rb_intern("descriptor");
|
44
|
+
ID_headers = rb_intern("headers");
|
45
|
+
ID_message = rb_intern("message");
|
46
|
+
ID_name_value = rb_intern("name_value");
|
47
|
+
ID_xml = rb_intern("xml");
|
48
|
+
ID_gsub = rb_intern("gsub");
|
49
|
+
ID_header_type = rb_intern("header_type");
|
50
|
+
}
|
51
|
+
|
52
|
+
void Message_build(PMQBYTE* pq_pp_buffer, PMQLONG pq_p_buffer_size, MQLONG trace_level,
|
53
|
+
VALUE parms, PPMQVOID pp_buffer, PMQLONG p_total_length, PMQMD pmqmd)
|
54
|
+
{
|
55
|
+
VALUE data;
|
56
|
+
VALUE descriptor;
|
57
|
+
VALUE headers;
|
58
|
+
VALUE message;
|
59
|
+
|
60
|
+
/* :data is an optional parameter, that if supplied overrides message.data */
|
61
|
+
data = rb_hash_aref(parms, ID2SYM(ID_data));
|
62
|
+
if(!NIL_P(data))
|
63
|
+
{
|
64
|
+
Check_Type(data, T_STRING);
|
65
|
+
*p_total_length = RSTRING_LEN(data);
|
66
|
+
*pp_buffer = RSTRING_PTR(data);
|
67
|
+
}
|
68
|
+
|
69
|
+
/* :message is optional */
|
70
|
+
message = rb_hash_aref(parms, ID2SYM(ID_message));
|
71
|
+
if(!NIL_P(message))
|
72
|
+
{
|
73
|
+
if (NIL_P(data)) /* Obtain data from message.data */
|
74
|
+
{
|
75
|
+
data = rb_funcall(message, ID_data, 0);
|
76
|
+
}
|
77
|
+
|
78
|
+
descriptor = rb_funcall(message, ID_descriptor, 0);
|
79
|
+
Check_Type(descriptor, T_HASH);
|
80
|
+
Message_to_mqmd(descriptor, pmqmd);
|
81
|
+
|
82
|
+
headers = rb_funcall(message, ID_headers, 0);
|
83
|
+
Check_Type(headers, T_ARRAY);
|
84
|
+
|
85
|
+
Check_Type(data, T_STRING);
|
86
|
+
|
87
|
+
/* Headers present? */
|
88
|
+
if ( !NIL_P(headers) &&
|
89
|
+
(NUM2LONG(rb_funcall(headers, ID_size, 0))>0) )
|
90
|
+
{
|
91
|
+
MQLONG data_offset = 0;
|
92
|
+
struct Message_build_header_arg arg;
|
93
|
+
VALUE next_header;
|
94
|
+
VALUE first_header;
|
95
|
+
VALUE header_type;
|
96
|
+
VALUE ind_val;
|
97
|
+
size_t index;
|
98
|
+
|
99
|
+
if(trace_level>2)
|
100
|
+
printf ("WMQ::Queue#put %ld Header(s) supplied\n", NUM2LONG(rb_funcall(headers, ID_size, 0)));
|
101
|
+
|
102
|
+
/* First sanity check: Do we even have enough space for the data being written and a small header */
|
103
|
+
if(RSTRING_LEN(data) + 128 >= *pq_p_buffer_size)
|
104
|
+
{
|
105
|
+
MQLONG new_size = RSTRING_LEN(data) + 512; /* Add space for data and a header */
|
106
|
+
if(trace_level>2)
|
107
|
+
printf ("WMQ::Queue#reallocate Resizing buffer from %ld to %ld bytes\n", *pq_p_buffer_size, (long)new_size);
|
108
|
+
|
109
|
+
*pq_p_buffer_size = new_size;
|
110
|
+
free(*pq_pp_buffer);
|
111
|
+
*pq_pp_buffer = ALLOC_N(unsigned char, new_size);
|
112
|
+
}
|
113
|
+
|
114
|
+
arg.pp_buffer = pq_pp_buffer;
|
115
|
+
arg.p_buffer_size = pq_p_buffer_size;
|
116
|
+
arg.data_length = RSTRING_LEN(data);
|
117
|
+
arg.p_data_offset = &data_offset;
|
118
|
+
arg.trace_level = trace_level;
|
119
|
+
arg.next_header_id = 0;
|
120
|
+
arg.data_format = pmqmd->Format;
|
121
|
+
|
122
|
+
if(trace_level>2)
|
123
|
+
printf ("WMQ::Queue#put Building %ld headers.\n", RARRAY_LEN(headers));
|
124
|
+
|
125
|
+
for(index = 0; index < RARRAY_LEN(headers); index++)
|
126
|
+
{
|
127
|
+
/*
|
128
|
+
* Look at the next Header so that this header can set it's format
|
129
|
+
* to that required for the next header.
|
130
|
+
*/
|
131
|
+
ind_val = LONG2FIX(index+1);
|
132
|
+
next_header = rb_ary_aref(1, &ind_val, headers);
|
133
|
+
|
134
|
+
if(NIL_P(next_header))
|
135
|
+
{
|
136
|
+
arg.next_header_id = 0;
|
137
|
+
}
|
138
|
+
else
|
139
|
+
{
|
140
|
+
header_type = rb_hash_aref(next_header, ID2SYM(ID_header_type));
|
141
|
+
if (!NIL_P(header_type))
|
142
|
+
{
|
143
|
+
arg.next_header_id = rb_to_id(header_type);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
ind_val = LONG2FIX(index);
|
148
|
+
Message_build_header(rb_ary_aref(1, &ind_val, headers), &arg);
|
149
|
+
}
|
150
|
+
|
151
|
+
/* Obtain Format of first header and copy in MQMD.Format */
|
152
|
+
ind_val = LONG2FIX(0);
|
153
|
+
first_header = rb_ary_aref(1, &ind_val, headers);
|
154
|
+
header_type = rb_hash_aref(first_header, ID2SYM(ID_header_type));
|
155
|
+
if (!NIL_P(header_type))
|
156
|
+
{
|
157
|
+
Message_build_set_format(rb_to_id(header_type), pmqmd->Format);
|
158
|
+
}
|
159
|
+
|
160
|
+
if(trace_level>2)
|
161
|
+
printf ("WMQ::Queue#put done building headers. Offset is now %ld\n", *arg.p_data_offset);
|
162
|
+
|
163
|
+
memcpy((*pq_pp_buffer) + data_offset, RSTRING_PTR(data), RSTRING_LEN(data));
|
164
|
+
*p_total_length = data_offset + RSTRING_LEN(data);
|
165
|
+
*pp_buffer = *pq_pp_buffer;
|
166
|
+
}
|
167
|
+
else
|
168
|
+
{
|
169
|
+
*p_total_length = RSTRING_LEN(data);
|
170
|
+
*pp_buffer = RSTRING_PTR(data);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
/* If :message is not supplied, then :data must be supplied in the parameter list */
|
174
|
+
else if(NIL_P(data))
|
175
|
+
{
|
176
|
+
rb_raise(rb_eArgError, "At least one of :message or :data is required.");
|
177
|
+
}
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
|
181
|
+
/*
|
182
|
+
* Extract MQMD from descriptor hash
|
183
|
+
*/
|
184
|
+
void Message_build_mqmd(VALUE self, PMQMD pmqmd)
|
185
|
+
{
|
186
|
+
Message_to_mqmd(rb_funcall(self, ID_descriptor, 0), pmqmd);
|
187
|
+
}
|
188
|
+
|
189
|
+
/*
|
190
|
+
* call-seq:
|
191
|
+
* new(...)
|
192
|
+
*
|
193
|
+
* Optional Named Parameters (as a single hash):
|
194
|
+
* * :data
|
195
|
+
* * Data to be written, or was read from the queue
|
196
|
+
* * :descriptor
|
197
|
+
* * Desciptor
|
198
|
+
*
|
199
|
+
* Example:
|
200
|
+
* message = WMQ::Message.new
|
201
|
+
*
|
202
|
+
* Example:
|
203
|
+
* message = WMQ::Message.new(:data=>'Hello World',
|
204
|
+
* :descriptor=> {
|
205
|
+
* :format => WMQ::MQFMT_STRING
|
206
|
+
* })
|
207
|
+
*/
|
208
|
+
VALUE Message_initialize(int argc, VALUE *argv, VALUE self)
|
209
|
+
{
|
210
|
+
VALUE parms = Qnil;
|
211
|
+
|
212
|
+
/* Extract optional parameter */
|
213
|
+
rb_scan_args(argc, argv, "01", &parms);
|
214
|
+
|
215
|
+
if (NIL_P(parms))
|
216
|
+
{
|
217
|
+
rb_iv_set(self, "@data", Qnil);
|
218
|
+
rb_iv_set(self, "@headers", rb_ary_new());
|
219
|
+
rb_iv_set(self, "@descriptor", rb_hash_new());
|
220
|
+
}
|
221
|
+
else
|
222
|
+
{
|
223
|
+
VALUE val;
|
224
|
+
Check_Type(parms, T_HASH);
|
225
|
+
|
226
|
+
rb_iv_set(self, "@data", rb_hash_aref(parms, ID2SYM(ID_data)));
|
227
|
+
|
228
|
+
val = rb_hash_aref(parms, ID2SYM(ID_headers));
|
229
|
+
if (NIL_P(val))
|
230
|
+
{
|
231
|
+
rb_iv_set(self, "@headers", rb_ary_new());
|
232
|
+
}
|
233
|
+
else
|
234
|
+
{
|
235
|
+
rb_iv_set(self, "@headers", val);
|
236
|
+
}
|
237
|
+
|
238
|
+
val = rb_hash_aref(parms, ID2SYM(ID_descriptor));
|
239
|
+
if (NIL_P(val))
|
240
|
+
{
|
241
|
+
rb_iv_set(self, "@headers", rb_hash_new());
|
242
|
+
}
|
243
|
+
else
|
244
|
+
{
|
245
|
+
rb_iv_set(self, "@descriptor", val);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
return Qnil;
|
250
|
+
}
|
251
|
+
|
252
|
+
/*
|
253
|
+
* Clear out the message data and headers
|
254
|
+
*
|
255
|
+
* Note:
|
256
|
+
* * The descriptor is not affected in any way
|
257
|
+
*/
|
258
|
+
VALUE Message_clear(VALUE self)
|
259
|
+
{
|
260
|
+
rb_iv_set(self, "@data", Qnil);
|
261
|
+
rb_iv_set(self, "@headers", rb_ary_new());
|
262
|
+
|
263
|
+
return self;
|
264
|
+
}
|
265
|
+
|
266
|
+
/*
|
267
|
+
* Automatically grow size of buffer to meet required size
|
268
|
+
* Existing data upto offset is preserved by copying to the new buffer
|
269
|
+
*
|
270
|
+
* additional_size: Size of any additional data to be written to this buffer
|
271
|
+
* EXCLUDING current offset and size of data to be written
|
272
|
+
*
|
273
|
+
* Returns pointer to new buffer incremented by offset within buffer
|
274
|
+
*/
|
275
|
+
PMQBYTE Message_autogrow_data_buffer(struct Message_build_header_arg* parg, MQLONG additional_size)
|
276
|
+
{
|
277
|
+
MQLONG size = *(parg->p_data_offset) + parg->data_length + additional_size;
|
278
|
+
/* Is buffer large enough for headers */
|
279
|
+
if(size >= *(parg->p_buffer_size))
|
280
|
+
{
|
281
|
+
PMQBYTE old_buffer = *(parg->pp_buffer);
|
282
|
+
size += 512; /* Additional space for subsequent headers */
|
283
|
+
|
284
|
+
if(parg->trace_level>2)
|
285
|
+
printf ("WMQ::Message Reallocating buffer from %ld to %ld\n", *(parg->p_buffer_size), (long)size);
|
286
|
+
|
287
|
+
*(parg->p_buffer_size) = size;
|
288
|
+
*(parg->pp_buffer) = ALLOC_N(char, size);
|
289
|
+
memcpy(*(parg->pp_buffer), old_buffer, *(parg->p_data_offset));
|
290
|
+
free(old_buffer);
|
291
|
+
}
|
292
|
+
return *(parg->pp_buffer) + *(parg->p_data_offset);
|
293
|
+
}
|
294
|
+
|
295
|
+
/*
|
296
|
+
* Concatenate the passed name or value element to the existing string
|
297
|
+
*/
|
298
|
+
static void Message_name_value_concat(VALUE string, VALUE element)
|
299
|
+
{
|
300
|
+
VALUE str = StringValue(element);
|
301
|
+
if (RSTRING_LEN(str) == 0) /* Empty String: "" */
|
302
|
+
{
|
303
|
+
rb_str_concat(string, rb_str_new2("\"\""));
|
304
|
+
}
|
305
|
+
else
|
306
|
+
{
|
307
|
+
void* contains_spaces = memchr(RSTRING_PTR(str),' ',RSTRING_LEN(str));
|
308
|
+
void* contains_dbl_quotes = memchr(RSTRING_PTR(str),'"',RSTRING_LEN(str));
|
309
|
+
|
310
|
+
if(contains_spaces == NULL && contains_dbl_quotes == NULL)
|
311
|
+
{
|
312
|
+
rb_str_concat(string, str);
|
313
|
+
}
|
314
|
+
else
|
315
|
+
{
|
316
|
+
VALUE quote = rb_str_new2("\"");
|
317
|
+
rb_str_concat(string, quote);
|
318
|
+
if(contains_dbl_quotes)
|
319
|
+
{
|
320
|
+
rb_str_concat(string, rb_funcall(str, ID_gsub, 2, quote, rb_str_new2("\"\"")));
|
321
|
+
}
|
322
|
+
else
|
323
|
+
{
|
324
|
+
rb_str_concat(string, str);
|
325
|
+
}
|
326
|
+
rb_str_concat(string, quote);
|
327
|
+
}
|
328
|
+
}
|
329
|
+
}
|
330
|
+
|
331
|
+
struct Message_build_rf_header_each_value_arg {
|
332
|
+
VALUE string;
|
333
|
+
VALUE key;
|
334
|
+
VALUE space;
|
335
|
+
};
|
336
|
+
|
337
|
+
static VALUE Message_build_rf_header_each_value(VALUE value, struct Message_build_rf_header_each_value_arg* parg)
|
338
|
+
{
|
339
|
+
Message_name_value_concat(parg->string, parg->key);
|
340
|
+
rb_str_concat(parg->string, parg->space);
|
341
|
+
Message_name_value_concat(parg->string, value);
|
342
|
+
rb_str_concat(parg->string, parg->space);
|
343
|
+
|
344
|
+
return Qnil;
|
345
|
+
}
|
346
|
+
|
347
|
+
static int Message_build_rf_header_each (VALUE key, VALUE value, VALUE string)
|
348
|
+
{
|
349
|
+
VALUE space = rb_str_new2(" ");
|
350
|
+
/* If Value is an Array, need to repeat name for each value */
|
351
|
+
if (TYPE(value) == T_ARRAY)
|
352
|
+
{
|
353
|
+
struct Message_build_rf_header_each_value_arg arg;
|
354
|
+
arg.key = key;
|
355
|
+
arg.string = string;
|
356
|
+
arg.space = space;
|
357
|
+
rb_iterate (rb_each, value, Message_build_rf_header_each_value, (VALUE)&arg);
|
358
|
+
}
|
359
|
+
else
|
360
|
+
{
|
361
|
+
Message_name_value_concat(string, key);
|
362
|
+
rb_str_concat(string, space);
|
363
|
+
Message_name_value_concat(string, value);
|
364
|
+
rb_str_concat(string, space);
|
365
|
+
}
|
366
|
+
return 0;
|
367
|
+
}
|
368
|
+
|
369
|
+
void Message_build_rf_header (VALUE hash, struct Message_build_header_arg* parg)
|
370
|
+
{
|
371
|
+
PMQBYTE p_data = *(parg->pp_buffer) + *(parg->p_data_offset);
|
372
|
+
|
373
|
+
static MQRFH MQRFH_DEF = {MQRFH_DEFAULT};
|
374
|
+
MQLONG name_value_len = 0;
|
375
|
+
PMQCHAR p_name_value = 0;
|
376
|
+
VALUE name_value = rb_hash_aref(hash, ID2SYM(ID_name_value));
|
377
|
+
|
378
|
+
MQRFH_DEF.CodedCharSetId = MQCCSI_INHERIT;
|
379
|
+
|
380
|
+
if(parg->trace_level>2)
|
381
|
+
printf ("WMQ::Message#build_rf_header Found rf_header\n");
|
382
|
+
|
383
|
+
if (!NIL_P(name_value))
|
384
|
+
{
|
385
|
+
if (TYPE(name_value) == T_HASH)
|
386
|
+
{
|
387
|
+
VALUE name_value_str = rb_str_buf_new(512); /* Allocate 512 char buffer, will grow as needed */
|
388
|
+
rb_hash_foreach(name_value, Message_build_rf_header_each, name_value_str);
|
389
|
+
name_value = name_value_str;
|
390
|
+
}
|
391
|
+
else if(TYPE(name_value) != T_STRING)
|
392
|
+
{
|
393
|
+
rb_raise(rb_eArgError, ":name_value supplied in rf_header to WMQ::Message#headers must be either a String or a Hash");
|
394
|
+
}
|
395
|
+
|
396
|
+
name_value_len = RSTRING_LEN(name_value);
|
397
|
+
if (name_value_len % 4) /* Not on 4 byte boundary ? */
|
398
|
+
{
|
399
|
+
rb_str_concat(name_value, rb_str_new(" ", 4 - (name_value_len % 4)));
|
400
|
+
name_value_len = RSTRING_LEN(name_value);
|
401
|
+
}
|
402
|
+
p_name_value = RSTRING_PTR(name_value);
|
403
|
+
}
|
404
|
+
|
405
|
+
p_data = Message_autogrow_data_buffer(parg, sizeof(MQRFH)+name_value_len);
|
406
|
+
|
407
|
+
memcpy(p_data, &MQRFH_DEF, sizeof(MQRFH));
|
408
|
+
Message_to_mqrfh(hash, (PMQRFH)p_data);
|
409
|
+
((PMQRFH)p_data)->StrucLength = sizeof(MQRFH) + name_value_len;
|
410
|
+
if(parg->next_header_id)
|
411
|
+
{
|
412
|
+
Message_build_set_format(parg->next_header_id, ((PMQRFH)p_data)->Format);
|
413
|
+
}
|
414
|
+
else
|
415
|
+
{
|
416
|
+
strncpy(((PMQRFH)p_data)->Format, parg->data_format, MQ_FORMAT_LENGTH);
|
417
|
+
}
|
418
|
+
|
419
|
+
*(parg->p_data_offset) += sizeof(MQRFH);
|
420
|
+
p_data += sizeof(MQRFH);
|
421
|
+
|
422
|
+
if(name_value_len)
|
423
|
+
{
|
424
|
+
memcpy(p_data, p_name_value, name_value_len);
|
425
|
+
*(parg->p_data_offset) += name_value_len;
|
426
|
+
}
|
427
|
+
|
428
|
+
if(parg->trace_level>3)
|
429
|
+
printf ("WMQ::Message#build_rf_header Sizeof namevalue string:%ld\n", (long)name_value_len);
|
430
|
+
|
431
|
+
if(parg->trace_level>2)
|
432
|
+
printf ("WMQ::Message#build_rf_header data offset:%ld\n", *(parg->p_data_offset));
|
433
|
+
}
|
434
|
+
|
435
|
+
static void Message_deblock_rf_header_each_pair(const char *p_name, const char *p_value, void* p_name_value_hash)
|
436
|
+
{
|
437
|
+
VALUE name_value_hash = (VALUE)p_name_value_hash;
|
438
|
+
VALUE key = rb_str_new2(p_name);
|
439
|
+
VALUE value = rb_str_new2(p_value);
|
440
|
+
|
441
|
+
/*
|
442
|
+
* If multiple values arrive for the same name (key) need to put values in an array
|
443
|
+
*/
|
444
|
+
VALUE existing = rb_hash_aref(name_value_hash, key);
|
445
|
+
if(NIL_P(existing))
|
446
|
+
{
|
447
|
+
rb_hash_aset(name_value_hash, key, value);
|
448
|
+
}
|
449
|
+
else
|
450
|
+
{
|
451
|
+
if(TYPE(existing) == T_ARRAY) /* Add to existing Array */
|
452
|
+
{
|
453
|
+
rb_ary_push(existing, value);
|
454
|
+
}
|
455
|
+
else /* Convert existing entry into an array */
|
456
|
+
{
|
457
|
+
VALUE array = rb_ary_new();
|
458
|
+
rb_ary_push(array, existing);
|
459
|
+
rb_ary_push(array, value);
|
460
|
+
rb_hash_aset(name_value_hash, key, array);
|
461
|
+
}
|
462
|
+
}
|
463
|
+
}
|
464
|
+
|
465
|
+
/*
|
466
|
+
* Deblock Any custom data following RF Header
|
467
|
+
* The RF Header has already been deblocked into hash
|
468
|
+
* p_data points to the beginning of the RF Header structure
|
469
|
+
*
|
470
|
+
* msg_len is the length of the remainder of the message from this header onwards
|
471
|
+
* It includes the length of any data that may follow
|
472
|
+
*
|
473
|
+
* Returns the length of RF Header plus the size of any custom data following it
|
474
|
+
*/
|
475
|
+
MQLONG Message_deblock_rf_header (VALUE hash, PMQBYTE p_data, MQLONG data_len)
|
476
|
+
{
|
477
|
+
MQLONG size = ((PMQRFH)p_data)->StrucLength;
|
478
|
+
VALUE name_value_hash = rb_hash_new();
|
479
|
+
|
480
|
+
rfh_toktype_t toktype;
|
481
|
+
|
482
|
+
if(size < 0 || size > data_len) /* Poison Message */
|
483
|
+
{
|
484
|
+
printf("WMQ::Message_deblock_rf_header StrucLength supplied in MQRFH exceeds total message length\n");
|
485
|
+
return 0;
|
486
|
+
}
|
487
|
+
|
488
|
+
toktype = rfh_decode_name_val_str(p_data + sizeof(MQRFH),
|
489
|
+
size - sizeof(MQRFH),
|
490
|
+
Message_deblock_rf_header_each_pair,
|
491
|
+
(void*)name_value_hash);
|
492
|
+
|
493
|
+
if (toktype != TT_END)
|
494
|
+
{
|
495
|
+
printf("Could not parse rfh name value string, reason %s\n",rfh_toktype_to_s(toktype));
|
496
|
+
}
|
497
|
+
|
498
|
+
rb_hash_aset(hash, ID2SYM(ID_name_value), name_value_hash);
|
499
|
+
|
500
|
+
return size;
|
501
|
+
}
|
502
|
+
|
503
|
+
/*
|
504
|
+
* RFH2 Header can contain multiple XML-like strings
|
505
|
+
* Message consists of:
|
506
|
+
* MQRFH2
|
507
|
+
* xml-string1-length (MQLONG)
|
508
|
+
* xml-string1 (Padded with spaces to match 4 byte boundary)
|
509
|
+
* xml-string2-length (MQLONG)
|
510
|
+
* xml-string2 (Padded with spaces to match 4 byte boundary)
|
511
|
+
* ....
|
512
|
+
*/
|
513
|
+
MQLONG Message_deblock_rf_header_2 (VALUE hash, PMQBYTE p_buffer, MQLONG data_len)
|
514
|
+
{
|
515
|
+
MQLONG size = ((PMQRFH2)p_buffer)->StrucLength;
|
516
|
+
PMQBYTE p_data = p_buffer + sizeof(MQRFH2);
|
517
|
+
PMQBYTE p_end = p_buffer + size; /* Points to byte after last character */
|
518
|
+
MQLONG xml_len = 0;
|
519
|
+
VALUE xml_ary = rb_ary_new();
|
520
|
+
|
521
|
+
PMQBYTE pChar;
|
522
|
+
size_t length;
|
523
|
+
size_t i;
|
524
|
+
|
525
|
+
if(size < 0 || size > data_len) /* Poison Message */
|
526
|
+
{
|
527
|
+
printf("WMQ::Message_deblock_rf_header_2 StrucLength supplied in MQRFH exceeds total message length\n");
|
528
|
+
return 0;
|
529
|
+
}
|
530
|
+
|
531
|
+
rb_hash_aset(hash, ID2SYM(ID_xml), xml_ary);
|
532
|
+
|
533
|
+
while(p_data < p_end)
|
534
|
+
{
|
535
|
+
xml_len = *(PMQLONG)p_data;
|
536
|
+
p_data += sizeof(MQLONG);
|
537
|
+
|
538
|
+
if (xml_len < 0 || p_data+xml_len > p_end)
|
539
|
+
{
|
540
|
+
printf("WMQ::Message#deblock_rf_header_2 Poison Message received, stopping further processing\n");
|
541
|
+
p_data = p_end;
|
542
|
+
}
|
543
|
+
else
|
544
|
+
{
|
545
|
+
/*
|
546
|
+
* Strip trailing spaces added as pad characters during put
|
547
|
+
*/
|
548
|
+
length = 0;
|
549
|
+
pChar = p_data + xml_len - 1;
|
550
|
+
for (i = xml_len; i > 0; i--)
|
551
|
+
{
|
552
|
+
if (*pChar != ' ')
|
553
|
+
{
|
554
|
+
length = i;
|
555
|
+
break;
|
556
|
+
}
|
557
|
+
pChar--;
|
558
|
+
}
|
559
|
+
rb_ary_push(xml_ary, rb_str_new(p_data, length));
|
560
|
+
p_data += xml_len;
|
561
|
+
}
|
562
|
+
}
|
563
|
+
|
564
|
+
return size;
|
565
|
+
}
|
566
|
+
|
567
|
+
static VALUE Message_build_rf_header_2_each(VALUE element, struct Message_build_header_arg* parg)
|
568
|
+
{
|
569
|
+
VALUE str = StringValue(element);
|
570
|
+
MQLONG length = RSTRING_LEN(str);
|
571
|
+
|
572
|
+
if (length % 4) /* Not on 4 byte boundary ? */
|
573
|
+
{
|
574
|
+
static const char * blanks = " ";
|
575
|
+
MQLONG pad = 4 - (length % 4);
|
576
|
+
MQLONG len = length + pad;
|
577
|
+
PMQBYTE p_data = Message_autogrow_data_buffer(parg, sizeof(len) + length + pad);
|
578
|
+
|
579
|
+
memcpy(p_data, (void*) &len, sizeof(len)); /* Start with MQLONG length indicator */
|
580
|
+
p_data += sizeof(len);
|
581
|
+
memcpy(p_data, RSTRING_PTR(str), length);
|
582
|
+
p_data += length;
|
583
|
+
memcpy(p_data, blanks, pad);
|
584
|
+
p_data += pad;
|
585
|
+
*(parg->p_data_offset) += sizeof(len) + length + pad;
|
586
|
+
}
|
587
|
+
else
|
588
|
+
{
|
589
|
+
PMQBYTE p_data = Message_autogrow_data_buffer(parg, sizeof(length) + length);
|
590
|
+
|
591
|
+
memcpy(p_data, (void*) &length, sizeof(length)); /* Start with MQLONG length indicator */
|
592
|
+
p_data += sizeof(length);
|
593
|
+
memcpy(p_data, RSTRING_PTR(str), length);
|
594
|
+
p_data += length;
|
595
|
+
*(parg->p_data_offset) += sizeof(length) + length;
|
596
|
+
}
|
597
|
+
|
598
|
+
return Qnil;
|
599
|
+
}
|
600
|
+
|
601
|
+
/*
|
602
|
+
* RFH2 Header can contain multiple XML-like strings
|
603
|
+
* Message consists of:
|
604
|
+
* MQRFH2
|
605
|
+
* xml-string1-length (MQLONG)
|
606
|
+
* xml-string1 (Padded with spaces to match 4 byte boundary)
|
607
|
+
* xml-string2-length (MQLONG)
|
608
|
+
* xml-string2 (Padded with spaces to match 4 byte boundary)
|
609
|
+
* ....
|
610
|
+
*
|
611
|
+
* The input data is either a String or an Array of Strings
|
612
|
+
* E.g.
|
613
|
+
*
|
614
|
+
* {
|
615
|
+
* :header_type =>:rf_header_2,
|
616
|
+
* :xml => '<hello>to the world</hello>'
|
617
|
+
* }
|
618
|
+
* OR
|
619
|
+
* {
|
620
|
+
* :header_type =>:rf_header_2,
|
621
|
+
* :xml => ['<hello>to the world</hello>', '<another>xml like string</another>'],
|
622
|
+
* }
|
623
|
+
*
|
624
|
+
*/
|
625
|
+
void Message_build_rf_header_2(VALUE hash, struct Message_build_header_arg* parg)
|
626
|
+
{
|
627
|
+
static MQRFH2 MQRFH2_DEF = {MQRFH2_DEFAULT};
|
628
|
+
MQLONG rfh2_offset = *(parg->p_data_offset);
|
629
|
+
PMQBYTE p_data;
|
630
|
+
VALUE xml = rb_hash_aref(hash, ID2SYM(ID_xml));
|
631
|
+
|
632
|
+
if(parg->trace_level>2)
|
633
|
+
printf ("WMQ::Message#build_rf_header_2 Found rf_header_2\n");
|
634
|
+
|
635
|
+
/* Add MQRFH2 Header, ensure that their is enough space */
|
636
|
+
p_data = Message_autogrow_data_buffer(parg, sizeof(MQRFH2));
|
637
|
+
memcpy(p_data, &MQRFH2_DEF, sizeof(MQRFH2));
|
638
|
+
Message_to_mqrfh2(hash, (PMQRFH2)p_data);
|
639
|
+
if(parg->next_header_id)
|
640
|
+
{
|
641
|
+
Message_build_set_format(parg->next_header_id, ((PMQRFH2)p_data)->Format);
|
642
|
+
}
|
643
|
+
else
|
644
|
+
{
|
645
|
+
memcpy(((PMQRFH2)p_data)->Format, parg->data_format, MQ_FORMAT_LENGTH);
|
646
|
+
}
|
647
|
+
*(parg->p_data_offset) += sizeof(MQRFH2);
|
648
|
+
|
649
|
+
if (!NIL_P(xml))
|
650
|
+
{
|
651
|
+
if(TYPE(xml) == T_ARRAY)
|
652
|
+
{
|
653
|
+
rb_iterate (rb_each, xml, Message_build_rf_header_2_each, (VALUE)parg);
|
654
|
+
}
|
655
|
+
else if(TYPE(xml) != T_STRING)
|
656
|
+
{
|
657
|
+
Message_build_rf_header_2_each(xml, parg);
|
658
|
+
}
|
659
|
+
else
|
660
|
+
{
|
661
|
+
rb_raise(rb_eArgError, ":name_value supplied in rf_header_2 to WMQ::Message#headers must be a String or an Array");
|
662
|
+
}
|
663
|
+
}
|
664
|
+
|
665
|
+
/* Set total length in MQRFH2 */
|
666
|
+
((PMQRFH)(*(parg->pp_buffer) + rfh2_offset))->StrucLength = *(parg->p_data_offset) - rfh2_offset;
|
667
|
+
|
668
|
+
if(parg->trace_level>2)
|
669
|
+
printf ("WMQ::Message#build_rf_header_2 data offset:%ld\n", *(parg->p_data_offset));
|
670
|
+
}
|
671
|
+
|