hessian2 1.1.1 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -2
  3. data/LICENSE.txt +22 -0
  4. data/README.md +161 -0
  5. data/hessian2.gemspec +3 -2
  6. data/lib/hessian2.rb +12 -4
  7. data/lib/hessian2/class_wrapper.rb +89 -0
  8. data/lib/hessian2/client.rb +38 -0
  9. data/lib/hessian2/constants.rb +164 -0
  10. data/lib/hessian2/em_client.rb +52 -0
  11. data/lib/hessian2/fault.rb +3 -0
  12. data/lib/hessian2/handler.rb +15 -0
  13. data/lib/hessian2/hessian_client.rb +3 -38
  14. data/lib/hessian2/parser.rb +619 -0
  15. data/lib/hessian2/struct_wrapper.rb +55 -0
  16. data/lib/hessian2/type_wrapper.rb +49 -8
  17. data/lib/hessian2/version.rb +1 -1
  18. data/lib/hessian2/writer.rb +498 -0
  19. data/spec/binary_spec.rb +51 -0
  20. data/spec/boolean_spec.rb +26 -0
  21. data/spec/class_wrapper_spec.rb +52 -0
  22. data/spec/create_monkeys.rb +14 -0
  23. data/spec/date_spec.rb +45 -0
  24. data/spec/double_spec.rb +78 -0
  25. data/spec/int_spec.rb +54 -0
  26. data/spec/list_spec.rb +66 -0
  27. data/spec/long_spec.rb +68 -0
  28. data/spec/map_spec.rb +36 -0
  29. data/spec/null_spec.rb +17 -0
  30. data/spec/object_spec.rb +65 -0
  31. data/spec/ref_spec.rb +43 -0
  32. data/spec/spec_helper.rb +23 -0
  33. data/spec/string_spec.rb +61 -0
  34. data/spec/struct_wrapper_spec.rb +47 -0
  35. data/spec/type_wrapper_spec.rb +102 -0
  36. data/test/app.rb +15 -0
  37. data/test/client.rb +9 -0
  38. data/test/config.ru +2 -0
  39. data/test/monkey_service.rb +12 -0
  40. metadata +79 -19
  41. data/README.rdoc +0 -21
  42. data/lib/hessian2/hessian_exception.rb +0 -3
  43. data/lib/hessian2/hessian_parser.rb +0 -75
  44. data/lib/hessian2/hessian_writer.rb +0 -130
  45. data/test/test_hessian_parser.rb +0 -56
@@ -0,0 +1,55 @@
1
+ module Hessian2
2
+ class StructWrapper
3
+ attr_reader :values
4
+
5
+ def initialize(klass, object)
6
+ raise "klass should not be nil: #{klass}" unless klass
7
+
8
+ if klass.is_a?(Array)
9
+ is_multi = true
10
+ members = klass.first.members
11
+ elsif klass.is_a?(String)
12
+ if klass.include?('[')
13
+ is_multi = true
14
+ members = Kernel.const_get(klass.delete('[]')).members
15
+ else
16
+ is_multi = false
17
+ members = Kernel.const_get(klass).members
18
+ end
19
+ else
20
+ is_multi = false
21
+ members = klass.members
22
+ end
23
+
24
+ if is_multi
25
+ values = []
26
+ object.each do |o|
27
+ values << get_values(members, o)
28
+ end
29
+ else
30
+ values = get_values(members, object)
31
+ end
32
+
33
+ @values = values
34
+ end
35
+
36
+
37
+ private
38
+
39
+ def get_values(members, object)
40
+ return nil unless object
41
+ values = []
42
+ if object.is_a?(Hash)
43
+ members.each{|f| values << (object[f] || object[f.to_s]) }
44
+ elsif object.instance_variable_get(:@attributes).is_a?(Hash)
45
+ attrs = object.attributes
46
+ members.each{|f| values << attrs[f.to_s] }
47
+ else
48
+ members.each{|f| values << object.instance_variable_get(f.to_s.prepend('@')) }
49
+ end
50
+
51
+ values
52
+ end
53
+
54
+ end
55
+ end
@@ -1,8 +1,49 @@
1
- module Hessian2
2
- class TypeWrapper
3
- attr_accessor :hessian_type, :object
4
- def initialize(hessian_type, object)
5
- @hessian_type, @object = hessian_type, object
6
- end
7
- end
8
- end
1
+ module Hessian2
2
+ class TypeWrapper
3
+ attr_accessor :object
4
+ attr_reader :hessian_type, :is_multi
5
+
6
+ def initialize(type, object)
7
+ if type.is_a?(Array)
8
+ is_multi = true
9
+ hessian_type = unify_type(type.first)
10
+ elsif type.is_a?(String)
11
+ if type.include?('[')
12
+ is_multi = true
13
+ hessian_type = unify_type(type.delete('[]'))
14
+ else
15
+ is_multi = false
16
+ hessian_type = unify_type(type)
17
+ end
18
+ else
19
+ is_multi = false
20
+ hessian_type = unify_type(type)
21
+ end
22
+
23
+ @object, @hessian_type, @is_multi = object, hessian_type, is_multi
24
+ end
25
+
26
+
27
+ def is_multi?
28
+ @is_multi
29
+ end
30
+
31
+
32
+ private
33
+
34
+ def unify_type(type)
35
+ case type
36
+ when 'L', 'l', 'Long', 'long', :long
37
+ 'L'
38
+ when 'I', 'i', 'Integer', 'int', :int
39
+ 'I'
40
+ when 'B', 'b', 'Binary', 'bin', :bin
41
+ 'B'
42
+ else
43
+ type
44
+ end
45
+ end
46
+
47
+
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Hessian2
2
- VERSION = "1.1.1"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -0,0 +1,498 @@
1
+ require 'hessian2/constants'
2
+ require 'bigdecimal'
3
+
4
+ module Hessian2
5
+ module Writer
6
+ include Constants
7
+
8
+ def call(method, args)
9
+ refs, crefs, trefs = {}, {}, {}
10
+ out = [ 'H', '2', '0', 'C' ].pack('ahha')
11
+ out << write_string(method)
12
+ out << write_int(args.size)
13
+ args.each{|arg| out << write(arg, refs, crefs, trefs) }
14
+
15
+ out
16
+ end
17
+
18
+
19
+ def reply(val)
20
+ [ 'H', '2', '0', 'R' ].pack('ahha') << write(val)
21
+ end
22
+
23
+
24
+ def write_fault(e)
25
+ val = {
26
+ code: e.class.to_s,
27
+ message: e.message,
28
+ detail: e.backtrace }
29
+ [ 'F' ].pack('a') << write_hash(val)
30
+ end
31
+
32
+
33
+ def write(val, refs = {}, crefs = {}, trefs = {})
34
+ case val
35
+ when StructWrapper # object to values-array
36
+ write_struct_wrapper(val, refs, crefs, trefs)
37
+ when ClassWrapper # class definition for statically typed languages
38
+ write_class_wrapper(val, refs, crefs, trefs)
39
+ when TypeWrapper
40
+ write_type_wrapper(val, refs, crefs, trefs)
41
+ when TrueClass
42
+ [ BC_TRUE ].pack('C')
43
+ when FalseClass
44
+ [ BC_FALSE ].pack('C')
45
+ when Time
46
+ if val.usec == 0 && val.sec == 0 # date in minutes
47
+ [ BC_DATE_MINUTE, val.to_i / 60 ].pack('CL>')
48
+ else
49
+ [ BC_DATE, val.to_i * 1000 + val.usec / 1000 ].pack('CQ>') # date
50
+ end
51
+ when Float, BigDecimal
52
+ write_float(val)
53
+ when Fixnum
54
+ write_int(val)
55
+ when Array
56
+ write_array(val, refs, crefs, trefs)
57
+ when Bignum
58
+ if val >= -0x80_000_000 && val <= 0x7f_fff_fff # four octet longs
59
+ [ BC_LONG_INT, val ].pack('Cl>')
60
+ else # long
61
+ [ BC_LONG, val ].pack('Cq>')
62
+ end
63
+ when Hash
64
+ write_hash(val, refs, crefs, trefs)
65
+ when NilClass
66
+ write_nil
67
+ when String
68
+ write_string(val)
69
+ when Symbol
70
+ write_string(val.to_s)
71
+ else
72
+ write_object(val, refs, crefs, trefs)
73
+ end
74
+ end
75
+
76
+
77
+ def print_string(str)
78
+ return str.b if String.method_defined?(:b)
79
+
80
+ arr, i = Array.new(str.bytesize), 0
81
+ str.unpack('U*').each do |c|
82
+ if c < 0x80 # 0xxxxxxx
83
+ arr[i] = c
84
+ elsif c < 0x800 # 110xxxxx 10xxxxxx
85
+ arr[i] = 0xc0 + ((c >> 6) & 0x1f)
86
+ arr[i += 1] = 0x80 + (c & 0x3f)
87
+ else # 1110xxxx 10xxxxxx 10xxxxxx
88
+ arr[i] = 0xe0 + ((c >> 12) & 0xf)
89
+ arr[i += 1] = 0x80 + ((c >> 6) & 0x3f)
90
+ arr[i += 1] = 0x80 + (c & 0x3f)
91
+ end
92
+ i += 1
93
+ end
94
+
95
+ arr.pack('C*')
96
+ end
97
+
98
+
99
+ def write_array(arr, refs = {}, crefs = {}, trefs = {})
100
+ idx = refs[arr.object_id]
101
+ return write_ref(idx) if idx
102
+
103
+ refs[arr.object_id] = refs.size
104
+ len = arr.size
105
+ if len <= LIST_DIRECT_MAX # [x78-7f] value*
106
+ str = [ BC_LIST_DIRECT_UNTYPED + len ].pack('C')
107
+ else # x58 int value*
108
+ str = [ BC_LIST_FIXED_UNTYPED ].pack('C') << write_int(len)
109
+ end
110
+
111
+ arr.each do |ele|
112
+ str << write(ele, refs, crefs, trefs)
113
+ end
114
+
115
+ str
116
+ end
117
+
118
+
119
+ def write_binary(str)
120
+ chunks, i, len = [], 0, str.size
121
+ while len > 0x8000
122
+ chunks << [ BC_BINARY_CHUNK, 0x8000 ].pack('Cn') << str[i...(i += 0x8000)]
123
+ len -= 0x8000
124
+ end
125
+
126
+ final = str[i..-1]
127
+ if len <= BINARY_DIRECT_MAX
128
+ chunks << [ BC_BINARY_DIRECT + len ].pack('C') << final
129
+ elsif len <= BINARY_SHORT_MAX
130
+ chunks << [ BC_BINARY_SHORT + (len >> 8), len ].pack('CC') << final
131
+ else
132
+ chunks << [ BC_BINARY, len ].pack('Cn') << final
133
+ end
134
+
135
+ chunks.join
136
+ end
137
+
138
+
139
+ def write_class_wrapper(val, refs, crefs, trefs)
140
+ return write_nil unless val.values
141
+
142
+ idx = refs[val.object_id]
143
+ return write_ref(idx) if idx
144
+
145
+ refs[val.object_id] = refs.size
146
+
147
+ if val.is_multi?
148
+ type = '[' << val.klass
149
+ if trefs.include?(type)
150
+ tstr = write_int(trefs[type])
151
+ else
152
+ trefs[type] = trefs.size # store a type
153
+ tstr = write_string(type)
154
+ end
155
+ return [ BC_LIST_DIRECT ].pack('C') << tstr if val.values.size == 0
156
+ end
157
+
158
+ cref = crefs[val.klass]
159
+ if cref
160
+ cidx = cref.first
161
+ fields = cref.last
162
+ str = ''
163
+ else
164
+ fstr = val.fields.map{|f| write_string(f) }.join
165
+
166
+ str = [ BC_OBJECT_DEF ].pack('C') << write_string(val.klass) << write_int(val.fields.size) << fstr
167
+ cidx = crefs.size
168
+ crefs[val.klass] = [cidx, val.fields] # store a class definition
169
+ end
170
+
171
+ if cidx <= OBJECT_DIRECT_MAX
172
+ cstr = [ BC_OBJECT_DIRECT + cidx ].pack('C')
173
+ else
174
+ cstr = [ BC_OBJECT ].pack('C') << write_int(cidx)
175
+ end
176
+
177
+ if val.is_multi?
178
+ len = val.values.size
179
+ if len <= LIST_DIRECT_MAX # [x70-77] type value*
180
+ str << [ BC_LIST_DIRECT + len ].pack('C') << tstr
181
+ else # 'V' type int value*
182
+ str << [ BC_LIST_FIXED ].pack('C') << tstr << write_int(len)
183
+ end
184
+
185
+ val.values.each do |ele|
186
+ if ele
187
+ ele_idx = refs[ele.object_id]
188
+ if ele_idx
189
+ str << (cstr + write_ref(ele_idx))
190
+ else
191
+ refs[ele.object_id] = refs.size
192
+ str << (cstr + ele.map{|v| write(v, refs, crefs, trefs)}.join)
193
+ end
194
+ else
195
+ str << write_nil
196
+ end
197
+ end
198
+ else
199
+ str << (cstr + val.values.map{|v| write(v, refs, crefs, trefs)}.join)
200
+ end
201
+
202
+ str
203
+ end
204
+
205
+
206
+ def write_float(val)
207
+ case val.infinite?
208
+ when 1
209
+ return [ BC_DOUBLE, Float::INFINITY ].pack('CG')
210
+ when -1
211
+ return [ BC_DOUBLE, -Float::INFINITY ].pack('CG')
212
+ else
213
+ return [ BC_DOUBLE, Float::NAN ].pack('CG') if val.nan?
214
+ return [ BC_DOUBLE_ZERO ].pack('C') if val.zero? # double zero
215
+ return [ BC_DOUBLE_ONE ].pack('C') if val == 1 # double one
216
+
217
+ ival = val.to_i
218
+ if ival == val
219
+ return [ BC_DOUBLE_BYTE, ival ].pack('Cc') if ival >= -0x80 && ival <= 0x7f # double octet
220
+ return [ BC_DOUBLE_SHORT, (ival >> 8), ival ].pack('Ccc') if ival >= -0x8000 && ival <= 0x7fff # double short
221
+ end
222
+
223
+ mval = val * 1000
224
+ if mval.finite?
225
+ mills = mval.to_i
226
+ if mills >= -0x80_000_000 && mills <= 0x7f_fff_fff && 0.001 * mills == val
227
+ return [ BC_DOUBLE_MILL, mills ].pack('Cl>') # double mill
228
+ end
229
+ end
230
+
231
+ [ BC_DOUBLE, val ].pack('CG') # double
232
+ end
233
+ end
234
+
235
+
236
+ def write_hash(hash, refs = {}, crefs = {}, trefs = {})
237
+ idx = refs[hash.object_id]
238
+ return write_ref(idx) if idx
239
+
240
+ refs[hash.object_id] = refs.size
241
+ str = [ BC_MAP_UNTYPED ].pack('C')
242
+ hash.each do |k, v|
243
+ str << write(k, refs, crefs, trefs)
244
+ str << write(v, refs, crefs, trefs)
245
+ end
246
+
247
+ str << [ BC_END ].pack('C')
248
+ end
249
+
250
+
251
+ def write_int(val)
252
+ if val >= INT_DIRECT_MIN && val <= INT_DIRECT_MAX # single octet integers
253
+ [ BC_INT_ZERO + val ].pack('c')
254
+ elsif val >= INT_BYTE_MIN && val <= INT_BYTE_MAX # two octet integers
255
+ [ BC_INT_BYTE_ZERO + (val >> 8), val ].pack('cc')
256
+ elsif val >= INT_SHORT_MIN && val <= INT_SHORT_MAX # three octet integers
257
+ [ BC_INT_SHORT_ZERO + (val >> 16), (val >> 8), val].pack('ccc')
258
+ elsif val >= -0x80_000_000 && val <= 0x7f_fff_fff # integer
259
+ [ BC_INT, val ].pack('Cl>')
260
+ else
261
+ [ BC_LONG, val ].pack('Cq>')
262
+ end
263
+ end
264
+
265
+
266
+ def write_long(val)
267
+ if val >= LONG_DIRECT_MIN && val <= LONG_DIRECT_MAX # single octet longs
268
+ [ BC_LONG_ZERO + val ].pack('c')
269
+ elsif val >= LONG_BYTE_MIN && val <= LONG_BYTE_MAX # two octet longs
270
+ [ BC_LONG_BYTE_ZERO + (val >> 8), val ].pack('cc')
271
+ elsif val >= LONG_SHORT_MIN && val <= LONG_SHORT_MAX # three octet longs
272
+ [ BC_LONG_SHORT_ZERO + (val >> 16), (val >> 8), val ].pack('ccc')
273
+ elsif val >= -0x80_000_000 && val <= 0x7f_fff_fff # four octet longs
274
+ [ BC_LONG_INT, val ].pack('Cl>')
275
+ else
276
+ [ BC_LONG, val ].pack('Cq>')
277
+ end
278
+ end
279
+
280
+
281
+ def write_nil
282
+ [ BC_NULL ].pack('C')
283
+ end
284
+
285
+
286
+ def write_object(object, refs = {}, crefs = {}, trefs = {})
287
+ return write_nil unless object
288
+
289
+ idx = refs[object.object_id]
290
+ return write_ref(idx) if idx
291
+
292
+ refs[object.object_id] = refs.size
293
+
294
+ klass = object.class.to_s
295
+ cref = crefs[klass]
296
+ if cref
297
+ cidx = cref.first
298
+ fields = cref.last
299
+ str = ''
300
+ else
301
+ fields = get_fields(object)
302
+ fstr = fields.map{|f| write_string(f) }.join
303
+ cidx = crefs.size
304
+ crefs[klass] = [cidx, fields]
305
+
306
+ str = [ BC_OBJECT_DEF ].pack('C') << write_string(klass) << write_int(fields.size) << fstr
307
+ end
308
+
309
+ if cidx <= OBJECT_DIRECT_MAX
310
+ cstr = [ BC_OBJECT_DIRECT + cidx ].pack('C')
311
+ else
312
+ cstr = [ BC_OBJECT ].pack('C') << write_int(cidx)
313
+ end
314
+
315
+ str << write_values(object, cstr, fields, refs, crefs, trefs)
316
+
317
+ str
318
+ end
319
+
320
+
321
+ def write_ref(val)
322
+ [ BC_REF ].pack('C') << write_int(val)
323
+ end
324
+
325
+
326
+ def write_struct_wrapper(val, refs, crefs, trefs)
327
+ return write_nil unless val.values
328
+
329
+ idx = refs[val.object_id]
330
+ return write_ref(idx) if idx
331
+
332
+ refs[val.object_id] = refs.size
333
+
334
+ write_array(val.values, refs, crefs, trefs)
335
+ end
336
+
337
+
338
+ def write_string(str)
339
+ chunks, i, len = '', 0, str.size
340
+ while len > 0x8000
341
+ chunks << [ BC_STRING_CHUNK, 0x8000 ].pack('Cn') << print_string(str[i...(i += 0x8000)])
342
+ len -= 0x8000
343
+ end
344
+
345
+ final = str[i..-1]
346
+ chunks << if len <= STRING_DIRECT_MAX
347
+ [ BC_STRING_DIRECT + len ].pack('C')
348
+ elsif len <= STRING_SHORT_MAX
349
+ [ BC_STRING_SHORT + (len >> 8), len ].pack('CC')
350
+ else
351
+ [ BC_STRING, len ].pack('Cn')
352
+ end
353
+
354
+ chunks << print_string(final)
355
+ end
356
+
357
+
358
+ def write_type_wrapped_array(arr, tstr, eletype, refs = {}, crefs = {}, trefs = {})
359
+ len = arr.size
360
+ return [ BC_LIST_DIRECT ].pack('C') << tstr if len == 0
361
+
362
+ if len <= LIST_DIRECT_MAX # [x70-77] type value*
363
+ str = [ BC_LIST_DIRECT + len ].pack('C') << tstr
364
+ else # 'V' type int value*
365
+ str = [ BC_LIST_FIXED ].pack('C') << tstr << write_int(len)
366
+ end
367
+
368
+ case eletype
369
+ when 'L'
370
+ arr.each do |ele|
371
+ str << write_long(Integer(ele))
372
+ end
373
+ when 'I'
374
+ arr.each do |ele|
375
+ str << write_int(Integer(ele))
376
+ end
377
+ when 'B'
378
+ arr.each do |ele|
379
+ str << write_binary(ele)
380
+ end
381
+ else
382
+ arr.each do |ele|
383
+ idx = refs[ele.object_id]
384
+ if idx
385
+ str << write_ref(idx)
386
+ else
387
+ refs[ele.object_id] = refs.size
388
+ str << write_type_wrapped_object(ele, tstr, refs, crefs, trefs)
389
+ end
390
+ end
391
+ end
392
+
393
+ str
394
+ end
395
+
396
+
397
+ def write_type_wrapped_object(object, tstr, refs = {}, crefs = {}, trefs = {})
398
+ return write_nil unless object
399
+
400
+ str = [ BC_MAP ].pack('C') << tstr
401
+
402
+ if object.is_a?(Hash)
403
+ object.each do |k, v|
404
+ str << write(k, refs, crefs, trefs)
405
+ str << write(v, refs, crefs, trefs)
406
+ end
407
+ elsif object.instance_variable_get(:@attributes).is_a?(Hash)
408
+ object.attributes.each do |k, v|
409
+ str << write(k, refs, crefs, trefs)
410
+ str << write(v, refs, crefs, trefs)
411
+ end
412
+ elsif object.is_a?(ClassWrapper)
413
+ object.fields.each_with_index do |f, i|
414
+ str << write(f, refs, crefs, trefs)
415
+ str << write(object.values[i], refs, crefs, trefs)
416
+ end
417
+ elsif object.is_a?(TypeWrapper)
418
+ object.object.each do |k, v|
419
+ str << write(k, refs, crefs, trefs)
420
+ str << write(v, refs, crefs, trefs)
421
+ end
422
+ else
423
+ object.instance_variables.each do |var|
424
+ str << write(var[1..-1], refs, crefs, trefs)
425
+ str << write(object.instance_variable_get(var), refs, crefs, trefs)
426
+ end
427
+ end
428
+
429
+ str << [ BC_END ].pack('C')
430
+ end
431
+
432
+
433
+ def write_type_wrapper(val, refs, crefs, trefs)
434
+ return write_nil unless val.object
435
+
436
+ idx = refs[val.object_id]
437
+ return write_ref(idx) if idx
438
+
439
+ refs[val.object_id] = refs.size
440
+
441
+ type = val.is_multi? ? ('[' << val.hessian_type) : val.hessian_type
442
+ if trefs.include?(type)
443
+ tstr = write_int(trefs[type])
444
+ else
445
+ trefs[type] = trefs.size
446
+ tstr = write_string(type)
447
+ end
448
+
449
+ if val.is_multi?
450
+ write_type_wrapped_array(val.object, tstr, val.hessian_type, refs, crefs, trefs)
451
+ else
452
+ case val.hessian_type
453
+ when 'L'
454
+ write_long(Integer(val.object))
455
+ when 'I'
456
+ write_int(Integer(val.object))
457
+ when 'B'
458
+ write_binary(val.object)
459
+ else
460
+ write_type_wrapped_object(val.object, tstr, refs, crefs, trefs)
461
+ end
462
+ end
463
+ end
464
+
465
+
466
+ private
467
+
468
+ def get_fields(object)
469
+ fields = if object.is_a?(Hash)
470
+ object.keys.map{|k| k.to_sym }
471
+ elsif object.instance_variable_get(:@attributes).is_a?(Hash)
472
+ object.attributes.keys.map{|k| k.to_sym }
473
+ else
474
+ object.instance_variables.map{|k| k[1..-1].to_sym }
475
+ end
476
+
477
+ raise "fields should not be empty: #{object.inspect}" if fields.empty?
478
+
479
+ fields
480
+ end
481
+
482
+
483
+ def write_values(object, cstr, fields, refs, crefs, trefs)
484
+ return write_nil unless object
485
+
486
+ vstr = if object.is_a?(Hash)
487
+ fields.map{|f| write(object[f] || object[f.to_s], refs, crefs, trefs) }.join
488
+ elsif object.instance_variable_get(:@attributes).is_a?(Hash)
489
+ fields.map{|f| write(object.attributes[f.to_s], refs, crefs, trefs) }.join
490
+ else
491
+ fields.map{|f| write(object.instance_variable_get(f.to_s.prepend('@')), refs, crefs, trefs) }.join
492
+ end
493
+
494
+ cstr + vstr
495
+ end
496
+
497
+ end
498
+ end