hessian2 1.1.1 → 2.0.1

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 (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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 453a51289b1c88074aa15ecbf5018cbece6297b5
4
+ data.tar.gz: 071db1c35b766485e0789ab22395769ac63cf652
5
+ SHA512:
6
+ metadata.gz: fd9256a1475ed060499bed2a415eca1eb2bfdb20d1a315935f93dfdd2bb5090bead4ff0820df0f106e8534c34b4e54cbebcf8abc10232d31647040247777fca2
7
+ data.tar.gz: 6624cba7d4093cec93d94d14a1dd82a5b39bce2340a6a229a0eaf4e045e88d2e5a29eeec03d8ad29c7b103841820939b13233433a40bf0332c3cc25ca4e26991
data/.gitignore CHANGED
@@ -1,6 +1,10 @@
1
1
  *.gem
2
2
  .bundle
3
3
  Gemfile.lock
4
+ doc/*
4
5
  pkg/*
5
- *.komodoproject
6
- .idea/
6
+ spec/*.yml
7
+ spec/*.jpg
8
+ test/*.data
9
+ test/*.txt
10
+ test/*.yml
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 takafan
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # hessian2
2
+
3
+ like json, additionally, 麻绳2 parse your object as a struct.
4
+
5
+ hessian2 implements hessian 2.0 protocol. look [web services protocol](http://hessian.caucho.com/doc/hessian-ws.html) and [serialization protocol](http://hessian.caucho.com/doc/hessian-serialization.html).
6
+
7
+ ## comparing
8
+
9
+ yajl-ruby: json, fast.
10
+
11
+ msgpack: binary, faster.
12
+
13
+ protobuf: encoding your object with schema.
14
+
15
+ marshal: powerful, fast, but ruby only.
16
+
17
+ hessian2: powerful as marshal but parse object to struct, clean api, smaller.
18
+
19
+ ## install
20
+
21
+ ```
22
+ gem install hessian2
23
+ ```
24
+
25
+ ## serializing
26
+
27
+ ```
28
+ require 'hessian2'
29
+ ```
30
+
31
+ ``` ruby
32
+ attributes = { born_at: Time.new(2009, 5, 8), name: '大鸡', price: 99.99 }
33
+ monkey = Monkey.new(attributes)
34
+ #=> #<Monkey id: nil, born_at: "2009-05-08 00:00:00", name: "\u5927\u9E21", price: #<BigDecimal:2b7c568,'0.9998999999 999999E2',27(45)>>
35
+
36
+ bin = Hessian2.write(monkey)
37
+ ```
38
+
39
+ ## deserializing
40
+
41
+ ``` ruby
42
+ monkey = Hessian2.parse(bin)
43
+ #=> #<struct id=nil, born_at=2009-05-08 00:00:00 +0800, name="\u5927\u9E21", price=99.99>
44
+ ```
45
+
46
+ ## struct wrapper
47
+
48
+ for hash and object, only send values that specified.
49
+
50
+ ``` ruby
51
+ MonkeyStruct = Struct.new(:born_at, :name)
52
+
53
+ wrapped_monkey = Hessian2::StructWrapper.new(MonkeyStruct, monkey)
54
+ bin = Hessian2.write(wrapped_monkey)
55
+ ```
56
+
57
+ parsing values-binary to a monkey struct
58
+
59
+ ``` ruby
60
+ monkey = Hessian2.parse(bin, MonkeyStruct)
61
+ #=> #<struct born_at=2009-05-08 00:00:00 +0800, name="\u5927\u9E21">
62
+ ```
63
+
64
+ monkeys
65
+
66
+ ``` ruby
67
+ wrapped_monkeys = Hessian2::StructWrapper.new([MonkeyStruct], monkeys)
68
+ bin = Hessian2.write(wrapped_monkeys)
69
+
70
+ monkeys = Hessian2.parse(bin, [MonkeyStruct])
71
+ ```
72
+
73
+ struct wrapper supports: hash, object, [hash, [object
74
+
75
+ ## class wrapper
76
+
77
+ for statically typed languages.
78
+
79
+ ``` ruby
80
+ wrapped_monkey = Hessian2::ClassWrapper.new('com.sun.java.Monkey', monkey)
81
+ ```
82
+
83
+ monkeys
84
+
85
+ ``` ruby
86
+ wrapped_monkeys = Hessian2::ClassWrapper.new('[com.sun.java.Monkey', monkeys)
87
+ ```
88
+
89
+ class wrapper supports: hash, object, [hash, [object
90
+
91
+ ## type wrapper
92
+
93
+ wrap a string to long
94
+
95
+ ``` ruby
96
+ str = '-0x8_000_000_000_000_000'
97
+ heslong = Hessian2::TypeWrapper.new(:long, str)
98
+ ```
99
+
100
+ wrap a file to binary
101
+
102
+ ``` ruby
103
+ binstr = IO.binread(File.expand_path("../Lighthouse.jpg", __FILE__))
104
+ hesbin = Hessian2::TypeWrapper.new(:bin, binstr)
105
+ ```
106
+
107
+ there are types: 'L', 'I', 'B', '[L', '[I', '[B', :long, :int, :bin, [:long], [:int], [:bin]
108
+
109
+ ## :symbolize_keys parser option
110
+
111
+ ``` ruby
112
+ bin = Hessian2.write(attributes)
113
+ hash = Hessian2.parse(bin, nil, symbolize_keys: true)
114
+ #=> {:born_at=>2009-05-08 00:00:00 +0800, :name=>"\u5927\u9E21", :price=>99.99}
115
+ ```
116
+
117
+ ## client
118
+
119
+ ``` ruby
120
+ url = 'http://127.0.0.1:9292/monkey'
121
+ client = Hessian2::Client.new(url)
122
+ ```
123
+
124
+ call remote method, send a monkey
125
+
126
+ ``` ruby
127
+ client.send_monkey(monkey)
128
+ ```
129
+
130
+ ## service
131
+
132
+ extend hessian handler
133
+
134
+ ``` ruby
135
+ class MonkeyService
136
+ extend Hessian2::Handler
137
+
138
+ def self.send_monkey(monkey)
139
+ # ...
140
+ end
141
+ ```
142
+
143
+ handle request
144
+
145
+ ``` ruby
146
+ post '/monkey' do
147
+ MonkeyService.handle(request.body.read)
148
+ end
149
+ ```
150
+
151
+ ## todo
152
+
153
+ on linux string slower than thrift
154
+
155
+ supports packet and envelope
156
+
157
+ write in c
158
+
159
+ ## authors
160
+
161
+ [takafan](http://hululuu.com)
data/hessian2.gemspec CHANGED
@@ -9,9 +9,10 @@ Gem::Specification.new do |s|
9
9
  s.email = ["takafan@163.com"]
10
10
  s.homepage = "http://github.com/takafan/hessian2"
11
11
  s.summary = %q{Hessian2}
12
- s.description = %q{implement hessian 1.0.2 specification. refactor Christer Sandberg's hessian, ruby 1.9.3 required.}
12
+ s.description = %q{like json, additionally, 麻绳2 parse your object as a struct.}
13
13
 
14
14
  s.rubyforge_project = "hessian2"
15
+ s.license = 'MIT'
15
16
 
16
17
  s.files = `git ls-files`.split("\n")
17
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -20,5 +21,5 @@ Gem::Specification.new do |s|
20
21
 
21
22
  # specify any dependencies here; for example:
22
23
  # s.add_development_dependency "rspec"
23
- # s.add_runtime_dependency "rest-client"
24
+ s.add_runtime_dependency "bigdecimal"
24
25
  end
data/lib/hessian2.rb CHANGED
@@ -1,6 +1,14 @@
1
- # http://hessian.caucho.com/doc/hessian-1.0-spec.xtp
2
-
3
- require "hessian2/version"
1
+ require 'hessian2/class_wrapper'
2
+ require 'hessian2/client'
3
+ require 'hessian2/fault'
4
+ require 'hessian2/handler'
4
5
  require 'hessian2/hessian_client'
6
+ require 'hessian2/parser'
7
+ require 'hessian2/struct_wrapper'
5
8
  require 'hessian2/type_wrapper'
6
- require 'hessian2/hessian_exception'
9
+ require 'hessian2/version'
10
+ require 'hessian2/writer'
11
+
12
+ module Hessian2
13
+ extend Parser, Writer
14
+ end
@@ -0,0 +1,89 @@
1
+ module Hessian2
2
+ class ClassWrapper
3
+ attr_reader :klass, :fields, :values, :is_multi
4
+
5
+ def initialize(klass, object)
6
+ raise 'klass should not be nil' unless klass
7
+
8
+ if klass.include?('[')
9
+ is_multi = true
10
+ klass.delete!('[]')
11
+
12
+ sample = object.select{|x| x}.first
13
+ unless sample # all nil
14
+ values = [ nil ] * object.size
15
+ else
16
+ fields = if sample.is_a?(Hash)
17
+ sample.keys.map{|k| k.to_sym }
18
+ elsif sample.instance_variable_get(:@attributes).is_a?(Hash)
19
+ sample.attributes.keys.map{|k| k.to_sym }
20
+ elsif sample.is_a?(ClassWrapper)
21
+ sample.fields
22
+ elsif sample.is_a?(TypeWrapper)
23
+ sample.object.keys.map{|k| k.to_sym }
24
+ else
25
+ sample.instance_variables.map{|k| k[1..-1].to_sym }
26
+ end
27
+
28
+ raise "fields should not be empty: #{object.inspect}" if fields.empty?
29
+
30
+ values = object.map do |obj|
31
+ if obj.nil?
32
+ nil
33
+ elsif obj.is_a?(Hash)
34
+ fields.map{|f| obj[f] || obj[f.to_s] }
35
+ elsif obj.instance_variable_get(:@attributes).is_a?(Hash)
36
+ fields.map{|f| obj.attributes[f.to_s] }
37
+ elsif obj.is_a?(ClassWrapper)
38
+ obj.values
39
+ elsif obj.is_a?(TypeWrapper)
40
+ fields.map{|f| obj.object[f] || obj.object[f.to_s] }
41
+ else
42
+ fields.map{|f| obj.instance_variable_get(f.to_s.prepend('@')) }
43
+ end
44
+ end
45
+ end
46
+ else
47
+ is_multi = false
48
+
49
+ if object
50
+ fields, values = [], []
51
+ if object.is_a?(Hash)
52
+ object.each do |k, v|
53
+ fields << k.to_sym
54
+ values << v
55
+ end
56
+ elsif object.instance_variable_get(:@attributes).is_a?(Hash)
57
+ object.attributes.each do |k, v|
58
+ fields << k.to_sym
59
+ values << v
60
+ end
61
+ elsif object.is_a?(ClassWrapper)
62
+ fields, values = object.fields, object.values
63
+ elsif object.is_a?(TypeWrapper)
64
+ object.object.each do |k, v|
65
+ fields << k.to_sym
66
+ values << v
67
+ end
68
+ else
69
+ object.instance_variables.each do |var|
70
+ k = var[1..-1]
71
+ fields << k.to_sym
72
+ values << object.instance_variable_get(k.prepend('@'))
73
+ end
74
+ end
75
+
76
+ raise "fields should not be empty: #{object.inspect}" if fields.empty?
77
+ end
78
+ end
79
+
80
+ @klass, @fields, @values, @is_multi = klass, fields, values, is_multi
81
+ end
82
+
83
+
84
+ def is_multi?
85
+ @is_multi
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,38 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'hessian2'
5
+
6
+ module Hessian2
7
+ class Client
8
+ attr_accessor :user, :password
9
+ attr_reader :scheme, :host, :port, :path, :proxy
10
+
11
+ def initialize(url, proxy = {})
12
+ uri = URI.parse(url)
13
+ @scheme, @host, @port, @path = uri.scheme, uri.host, uri.port, uri.path.empty? ? '/' : uri.path
14
+ @path += "?#{uri.query}" if uri.query
15
+ raise "Unsupported Hessian protocol: #{@scheme}" unless %w(http https).include?(@scheme)
16
+ @proxy = proxy
17
+ end
18
+
19
+
20
+ def method_missing(id, *args)
21
+ return invoke(id.id2name, args)
22
+ end
23
+
24
+
25
+ private
26
+
27
+ def invoke(method, args)
28
+ req = Net::HTTP::Post.new(@path, { 'Content-Type' => 'application/binary' })
29
+ req.basic_auth @user, @password if @user
30
+ conn = Net::HTTP.new(@host, @port, *@proxy.values_at(:host, :port, :user, :password))
31
+ conn.use_ssl = true and conn.verify_mode = OpenSSL::SSL::VERIFY_NONE if @scheme == 'https'
32
+ conn.start do |http|
33
+ Hessian2.parse_rpc(http.request(req, Hessian2.call(method, args)).body)
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,164 @@
1
+ module Hessian2
2
+ #=== Hessian 2.0 Web Services Protocol Bytecode map
3
+ #
4
+ # x00 - x42 # reserved
5
+ # x43 # rpc call ('C')
6
+ # x44 # reserved
7
+ # x45 # envelope ('E')
8
+ # x46 # fault ('F')
9
+ # x47 # reserved
10
+ # x48 # hessian version ('H')
11
+ # x49 - x4f # reserved
12
+ # x4f # packet chunk ('O')
13
+ # x50 # packet end ('P')
14
+ # x51 # reserved
15
+ # x52 # rpc result ('R')
16
+ # x53 - x59 # reserved
17
+ # x5a # terminator ('Z')
18
+ # x5b - x5f # reserved
19
+ # x70 - x7f # final packet (0 - 4096)
20
+ # x80 - xff # final packet for envelope (0 - 127)
21
+ #
22
+ #=== Hessian 2.0 Serialization Protocol Bytecode map
23
+ #
24
+ # x00 - x1f # utf-8 string length 0-31*
25
+ # x20 - x2f # binary data length 0-15*
26
+ # x30 - x33 # utf-8 string length 0-1023
27
+ # x34 - x37 # binary data length 0-1023
28
+ # x38 - x3f # three-octet compact long (-x40000 to x3ffff)
29
+ # x40 # reserved (expansion/escape)
30
+ # x41 # 8-bit binary data non-final chunk ('A')
31
+ # x42 # 8-bit binary data final chunk ('B')
32
+ # x43 # object type definition ('C')
33
+ # x44 # 64-bit IEEE encoded double ('D')
34
+ # x45 # reserved
35
+ # x46 # boolean false ('F')
36
+ # x47 # reserved
37
+ # x48 # untyped map ('H')
38
+ # x49 # 32-bit signed integer ('I')
39
+ # x4a # 64-bit UTC millisecond date
40
+ # x4b # 32-bit UTC minute date
41
+ # x4c # 64-bit signed long integer ('L')
42
+ # x4d # map with type ('M')
43
+ # x4e # null ('N')
44
+ # x4f # object instance ('O')
45
+ # x50 # reserved
46
+ # x51 # reference to map/list/object - integer ('Q')
47
+ # x52 # utf-8 string non-final chunk ('R')
48
+ # x53 # utf-8 string final chunk ('S')
49
+ # x54 # boolean true ('T')
50
+ # x55 # variable-length list/vector ('U')
51
+ # x56 # fixed-length list/vector ('V')
52
+ # x57 # variable-length untyped list/vector ('W')
53
+ # x58 # fixed-length untyped list/vector ('X')
54
+ # x59 # long encoded as 32-bit int ('Y')
55
+ # x5a # list/map terminator ('Z')
56
+ # x5b # double 0.0
57
+ # x5c # double 1.0
58
+ # x5d # double represented as byte (-128.0 to 127.0)
59
+ # x5e # double represented as short (-32768.0 to 32767.0)
60
+ # x5f # double represented as float
61
+ # x60 - x6f # object with direct type
62
+ # x70 - x77 # fixed list with direct length
63
+ # x78 - x7f # fixed untyped list with direct length
64
+ # x80 - xbf # one-octet compact int (-x10 to x2f, x90 is 0)*
65
+ # xc0 - xcf # two-octet compact int (-x800 to x7ff)
66
+ # xd0 - xd7 # three-octet compact int (-x40000 to x3ffff)
67
+ # xd8 - xef # one-octet compact long (-x8 to xf, xe0 is 0)
68
+ # xf0 - xff # two-octet compact long (-x800 to x7ff, xf8 is 0)
69
+ module Constants
70
+ BC_BINARY = 0x42
71
+ BC_BINARY_CHUNK = 0x41
72
+ BC_BINARY_DIRECT = 0x20
73
+ BINARY_DIRECT_MAX = 0x0f
74
+ BC_BINARY_SHORT = 0x34
75
+ BINARY_SHORT_MAX = 0x3ff
76
+
77
+ BC_CLASS_DEF = 0x43
78
+
79
+ BC_DATE = 0x4a
80
+ BC_DATE_MINUTE = 0x4b
81
+
82
+ BC_DOUBLE = 0x44
83
+
84
+ BC_DOUBLE_ZERO = 0x5b
85
+ BC_DOUBLE_ONE = 0x5c
86
+ BC_DOUBLE_BYTE = 0x5d
87
+ BC_DOUBLE_SHORT = 0x5e
88
+ BC_DOUBLE_MILL = 0x5f
89
+
90
+ BC_FALSE = 0x46
91
+
92
+ BC_INT = 0x49
93
+
94
+ INT_DIRECT_MIN = -0x10
95
+ INT_DIRECT_MAX = 0x2f
96
+ BC_INT_ZERO = 0x90
97
+
98
+ INT_BYTE_MIN = -0x800
99
+ INT_BYTE_MAX = 0x7ff
100
+ BC_INT_BYTE_ZERO = 0xc8
101
+
102
+ BC_END = 0x5a
103
+
104
+ INT_SHORT_MIN = -0x40000
105
+ INT_SHORT_MAX = 0x3ffff
106
+ BC_INT_SHORT_ZERO = 0xd4
107
+
108
+ BC_LIST_VARIABLE = 0x55
109
+ BC_LIST_FIXED = 0x56
110
+ BC_LIST_VARIABLE_UNTYPED = 0x57
111
+ BC_LIST_FIXED_UNTYPED = 0x58
112
+
113
+ BC_LIST_DIRECT = 0x70
114
+ BC_LIST_DIRECT_UNTYPED = 0x78
115
+ LIST_DIRECT_MAX = 0x7
116
+
117
+ BC_LONG = 0x4c
118
+ LONG_DIRECT_MIN = -0x08
119
+ LONG_DIRECT_MAX = 0x0f
120
+ BC_LONG_ZERO = 0xe0
121
+
122
+ LONG_BYTE_MIN = -0x800
123
+ LONG_BYTE_MAX = 0x7ff
124
+ BC_LONG_BYTE_ZERO = 0xf8
125
+
126
+ LONG_SHORT_MIN = -0x40000
127
+ LONG_SHORT_MAX = 0x3ffff
128
+ BC_LONG_SHORT_ZERO = 0x3c
129
+
130
+ BC_LONG_INT = 0x59
131
+
132
+ BC_MAP = 0x4d
133
+ BC_MAP_UNTYPED = 0x48
134
+
135
+ BC_NULL = 0x4e
136
+
137
+ BC_OBJECT = 0x4f
138
+ BC_OBJECT_DEF = 0x43
139
+
140
+ BC_OBJECT_DIRECT = 0x60
141
+ OBJECT_DIRECT_MAX = 0x0f
142
+
143
+ BC_REF = 0x51
144
+
145
+ BC_STRING = 0x53
146
+ BC_STRING_CHUNK = 0x52
147
+
148
+ BC_STRING_DIRECT = 0x00
149
+ STRING_DIRECT_MAX = 0x1f
150
+ BC_STRING_SHORT = 0x30
151
+ STRING_SHORT_MAX = 0x3ff
152
+
153
+ BC_TRUE = 0x54
154
+
155
+ P_PACKET_CHUNK = 0x4f
156
+ P_PACKET = 0x50
157
+
158
+ P_PACKET_DIRECT = 0x80
159
+ PACKET_DIRECT_MAX = 0x7f
160
+
161
+ P_PACKET_SHORT = 0x70
162
+ PACKET_SHORT_MAX = 0xfff
163
+ end
164
+ end