timfel/ruby-hessian
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
= Ruby Hessian Client
This is a Ruby implementation of the Hessian Binary Web Service Protocol.
== What is Hessian?
Here's the description from the Hessian site at
{http://www.caucho.com/hessian}[http://www.caucho.com/hessian].
<em>The Hessian binary web service protocol makes web services usable without
requiring a large framework, and without learning yet another alphabet soup of
protocols. Because it is a binary protocol, it is well-suited to sending binary
data without any need to extend the protocol with attachments.</em>
Please consult the Hessian[http://www.caucho.com/hessian] home page or the
{Hessian 1.0.2}[http://www.caucho.com/resin-3.0/protocols/hessian-1.0-spec.xtp]
specification for more information.
== Usage
The Hessian Ruby Client acts as a proxy for remote calls to Hessian services.
Hessian services are identified by URI's and the Ruby Hessian Client supports
the http and https schemes. A call to a Hessian service is made like a regular
method invocation in Ruby, and the Ruby Hessian Client will transparently
serialize and deserialize to and from Ruby types.
Hessian's object serialization has 13 types, and the following mappings are
used in the Ruby Hessian Client.
The 9 primitive types:
binary:: Hessian::Binary
boolean:: TrueClass or FalseClass
date:: Time
double:: Float
int:: Integer
long:: Integer
remote:: Not implemented!
string:: String
xml:: String
The 2 combining types:
list:: Array
map:: Hash
Finally, the 2 special constructs:
null:: NilClass
ref:: The type referenced
The combining Hessian types can be given an explicit type understood by the
service. This can be used to specify that a list only contain strings for
example, or more importantly - this is how to serialize custom types.
A <i>custom type</i> in this context is all types not conforming to the 13
types above, such as your own objects etc.
Custom types are serialized using the +map+ with an explicit type
specified and the underlying Ruby type must be a Hash. To specifiy an explicit
type wrap the object in a Hessian::TypeWrapper or create the method
+hessian_type+ on that object. See the examples below.
The Ruby Hessian Client will automatically convert instances of the Struct
class to a Hash but for all other custom types you must create the conversion.
When a service reply (i.e. the return type of the method called) is a custom
type, the Ruby Hessian Client will always return a Hash since the type returned
might be unknown in Ruby. You may then convert that Hash to suite your needs.
Errors in a call to a Hessian service will result in a fault that is wrapped as
a Hessian::HessianException.
== Examples
To create a Hessian::HessianClient instance:
client = Hessian::HessianClient.new('http://localhost:8080/echo')
To specify a user and a password for basic authentication:
client.user, client.password = 'foo', 'bar'
To create a Hessian::HessianClient using a proxy:
proxy = { :host => 'proxy.foo.bar', :port => '80' }
client = Hessian::HessianClient.new('http://localhost:8080/echo, proxy)
The valid symbol keys for the proxy hash are:
[:host] Proxy host
[:port] Proxy port
[:user] Proxy user
[:password] Proxy password
Let's say that the service bound to <tt>/echo</tt> is the following:
class Echo
def echo(msg)
"Echo reply: #{msg}"
end
end
Then invoking the service call +echo+:
client.echo('hessian') => "Echo reply: hessian"
=== Explicit types
To specify an <i>explicitly typed</i> list as a Java string array
for example (where +foo+ is a method on the Java service used):
list = %w(one two three)
client.foo(Hessian::TypeWrapper.new('[string', list))
or
list = %w(one two three)
def list.hessian_type
'[string'
end
client.foo(list)
Let's pretend that we want to call a Java service that has the following
interface:
public interface PersonService implements Serializable {
public Person addPerson(Person person);
}
and where the Person is defined as (could be a JavaBean as well):
public interface Person implements Serializable {
public int age;
public String name;
}
+Person+ is a custom type so we need to send a Hash with an explicit type
specified:
person = { 'age' => 32, 'name' => 'Christer Sandberg' }
reply = client.addPerson(Hessian::TypeWrapper.new('Person', person))
The Ruby Hessian Client will automatically convert a Struct to a Hash so the
following will also work:
person = Struct.new(:age, :name)[32, 'Christer Sandberg']
class << person
def hessian_type
'Person'
end
end
reply = client.addPerson(person)
The result from these invocations would be a Hash:
reply => { 'age' => 32, 'name' => 'Christer Sandberg' }