Since SOAP was first introduced, dozens of implementations have appeared for a whole host of languages. Virtually any system that can handle XML data and communicate using HTTP can be a viable platform to use SOAP, and the wide interest in integrating XML and "web capabilities" means that many languages are viable for use as clients and as servers.
In this chapter, we take a detailed look at the use of SOAP with the Ruby language, looking at:
- An example client to access services on the Internet using SOAP4R
- A client/server using SOAP4R q A client for Google search using SOAP4R
- A basic client/server application using xmlrpc4r
We later move on to the practical application and use of Web Services in embedded systems like mobile phones and PDAs. In this section we will explore the following:
- Use of XML Pull Parsers
- Using kSOAP with applets
- Using kSOAP in embedded systems
Introduction to Ruby
Ruby is an object-oriented language and its semantics are derived largely from Smalltalk, where everything, including numbers, iterators, and closures, is an object. Ruby then drops Smalltalk syntax in favor of a more traditional Algol-like syntax, borrowing syntax from languages such as Perl, Eiffel, and Ada. In Ruby, absolutely everything you manipulate is an object and ultimately everything is inherited from the Object class, including complex data structures, functions, control structures such as iterators, and even numbers.
In Ruby, there are no standalone functions; all functions are associated with some object class, and are thus methods, which makes it a true object-oriented language. More information about Ruby can be found at http://www.ruby-lang.org/ and http://dev.rubycentral.com/faq/rubyfaq.html.
The language design attempts to follow the Principle of Least Surprise or Law of Least Astonishment, where things are designed to work the way one would expect, aiming to minimize the incidence of special rules or exceptions. This may be contrasted with the designs of other languages:
- Perl was originally designed to combine the syntaxes of a number of languages and text processing tools such as awk, sed, tr, C, grep, and sh, with the result that a lot of the language represents "special rules" indicating the similarities to and differences between Perl and the languages from which it was derived.
- C++, as an extension of C, as well as a codification of numerous extensions developed by many C++ vendors, similarly involves a lot of special rules and exceptions.
- The design of Java, almost exclusively influenced by one vendor, leads to it having somewhat fewer "design exceptions" than Perl or C++. Nevertheless, there are irregularities in Java particularly relating to the differing treatments of numeric types such as int versus Integer, which sometimes does lead to some degree of astonishment.
Ruby did not start with the same sorts of expectations of compatibility with existing languages in its design, and as a result the designers could choose features they liked without any pressure to force particular features to fit. And unlike Python and Java, Ruby starts and ends with all data structures being objects, which improves the consistency of behavior.
One of the characteristic advantages of scripting languages over traditional compiled language families like C and Pascal is that they provide automatic dynamic memory allocation, allocating space for values on demand, and de-allocating them when they are no longer referenced. Perl and Python use reference counting, which is simple to understand and implement, but it leaks memory if self-referencing data structures do not manually break those self-references. Ruby goes further than that, using a mark and sweep garbage collection approach much like those used in Lisp, and does not suffer from such leaks.
The object model of Ruby is different than those of C++, Java, and such, and a fair bit of insight may be gotten by looking at Ruby's handling of the traditionally controversial problem of multiple inheritances. The problem comes when an object is created that inherits attributes and methods from multiple parent classes; here sometimes the inheritance hierarchy becomes ambiguous.
C++ supports multiple inheritances, and some of its considerable complexity arises from the need to provide ways to refer to the multiple methods and attributes. On the other hand Java rejects multiple inheritance, allowing classes to inherit only from a single immediate parent. Ruby uses the notion of mixins, allowing a class to include methods from additional modules, with the result that methods are mixed in together.
Ambiguity is dealt with by the notion that the last method included is what is used. Here is an example of this. We start by defining three modules that modify an attribute @Value. Here is the first module:
#!/usr/bin/ruby
module Mod1
def foo
@Value = 1
@V1 = 1
end
end
Here is the second module:
module Mod2
def foo
@Value = 2
@V2 = 2
end
end
And here is the third module:
module Mod3
def foo
@Value = 3
@V3 = 3
end
end
All the three modules above have the same method, foo(), modifying the same attribute, @Value, and each setting up its own attribute. Now, we will mix them together:
class Bar
include Mod1
include Mod3
include Mod2
def initialize
self.foo
end
def getValue
return [@Value, @V1, @V2, @V3]
end
end
a = Bar.new;
v = a.getValue
print "Result of getValue:\n"
v.each do |value|
print value, " "
end
print "\n"
Since the three modules have the same method, foo(), the final one included, Mod2, is what provides the foo() method, and so @Value takes the value 2, and of @V1, @V2, and @V3, the only one defined is @V2. To run this, use the command ruby mixinsamp.rb, that produces the output as follows:
Result of getValue:
2 nil 2 nil
Switching to a different module to be included last changes the output variously to 3 nil nil 3, 2 nil 2 nil, or 1 1 nil nil.
This fits in quite well with the Principle of Least Surprise for a module mixed in last to override methods and values from earlier modules is certainly a logical approach.
The authors of the book Programming Ruby from Addison-Wesley (ISBN 0-201710-89-7) introduce the language with the comment: 'Use Ruby, and you'll write better code, be more productive, and enjoy programming more.' Such dramatic results cannot be guaranteed for everyone, but there certainly is a lot to like about Ruby.
SOAP4R
The SOAP implementation available for Ruby is called SOAP4R. SOAP4R was first released in July 2000, and has had over a dozen updates including fixes based on interoperability testing. Its latest version at the time of writing was version 1.4.4 released in May 2002.
SOAP4R does not yet support the following SOAP 1.1 features:
- SOAP actor attribute
- SOAP mustUnderstand attribute
- SOAP Fault codes
- SOAP XML Schema encoding
- SOAP transports other than HTTP
Nor does it support SSL, HTTP Authentication, layered standards like WSDL or UDDI, or the sorts of extended transport mechanisms (such SMTP, POP3, libz compression, and Jabber) found in SOAP::Lite. Some of these mechanisms should come as development progresses.
Development has been quite active, but expecting WSDL or UDDI support immediately may be too much to ask. Updates are frequently improving functionality and interoperability, which is quite encouraging.