Tuscany SCA Native - Ruby Extension

The Tuscany Ruby extension allows Ruby scripts to be used as components in SCA composites and as clients that can invoke SCA services.

The following samples demonstrate use of the Ruby extension:

System Requirements

In order to install and use the Tuscany SCA Ruby Extension there are some extra requirements in addition to the Tuscany SCA requirements:

Software Download Link
Ruby version 1.8.x http://www.ruby-lang.org
Please download and follow the installation instructions. You should be able to build the Tuscany SCA Ruby Extension with other versions of Ruby. The extension has been tested with the Ruby 1.8.5 One-Click Installer on Windows and the 1.8.5 source code (compiled locally) on Linux.

Installing the Tuscany SCA Ruby Extension

Getting the Tuscany SCA Ruby Extension working with the binary release on Linux and Mac OS X

  1. Ensure the Ruby libraries are available on the PATH environment variable

Getting the Tuscany SCA Ruby Extension working with the source release on Linux and Mac OS X

  1. You will need the Tuscany SCA and SDO libraries - follow the instructions here to build the SCA libraries and default extensions
  2. The following environment variables are required:
    • TUSCANY_SCACPP=<path to built Tuscany SCA>
    • TUSCANY_SDOCPP=<path to installed Tuscany SDO>
    • RUBY_LIB=<path to Ruby libraries>
    • RUBY_INCLUDE=<path to Ruby includes>
      Note: If you are using a default installation of Ruby these are usually:
      RUBY_LIB=/usr/lib
      RUBY_INCLUDE=/usr/lib/ruby/1.8/i386-linux
  3. Build the Ruby source only with the following command sequence:
    • cd <tuscany_sca_install_dir>
    • ./configure --prefix=$TUSCANY_SCACPP --enable-ruby --enable-cpp=no --enable-wsbinding=no
    • make
    • make install
    NOTE: If you don't provide a --prefix configure option, it will by default install into /usr/local/tuscany/sca

Getting the Tuscany SCA Ruby Extension working with the binary release on Windows

  1. Ensure the Ruby libraries are available on the PATH environment variable

Getting the Tuscany SCA Ruby Extension working with the source release on Windows

  1. Unzip the supplied source zip file
  2. The following environment variables are required:
    • TUSCANY_SCACPP=<path to built Tuscany SCA>
    • TUSCANY_SDOCPP=<path to installed Tuscany SDO>
    • RUBY_HOME=<path to installed Ruby>
  3. You must have set up the environment for Microsoft Visual C++ tools. The build command will call vcvars32 to set the environment. Ensure the directory containing this is on your path. This will be where you installed the compiler.
  4. Build the source:
    • cd <to where you unzipped the source>
    • build
    This will build all the projects and put the required output into the 'deploy' directory

    Alternatively, open the workspace at <tuscany_sca_install_dir>/projects/tuscany_sca/tuscany_sca.dsw in Visual Studio 6 or at at <tuscany_sca_install_dir>/projectsvc7/tuscany_sca/tuscany_sca.sln in Visual Studio 7.1 - you can build projects individually or build the samples to rebuild all the projects

The Tuscany Ruby Programming Model

This section will explain the Tuscany Ruby programming model to help you to write your own Ruby components and clients.

The Tuscany Ruby component and client support comes from a Ruby extension library that is built in the <tuscany_sca_install_dir>/extensions/ruby/bin directory on Windows and <tuscany_sca_install_dir>/extensions/ruby/lib on Linux and Mac OS X.

Clients

Using the Ruby SCA extension library, a Ruby client can search for an SCA service with:

require("libtuscany_sca_ruby")

calculator = SCA::locateService("CalculatorComponent/CalculatorService")

This finds the component and service as defined in the composite and componentType side files and returns a proxy object that can call the SCA service. You can then simply call a business method on "calculator", like this:

result = calculator.add(12.3, 45.6)

Components

Ruby component implementations are standard Ruby scripts, where class-level functions or module-level functions can be invoked by the Tuscany runtime. To use a Ruby component implementation, use the implementation.ruby element in your .composite file. For example:

<implementation.ruby script="CalculatorImpl.rb"/>

To instantiate a class instance and use a class-level function, the Ruby class must have a default constructor (an initialize() method that takes no arguments) and the class attribute must be definde in the implementation.ruby element in your composite, like so:

<implementation.ruby script="CalculatorImpl.rb" class="CalculatorImpl"/>

Tuscany currently supports passing simple types (strings, ints, floats, etc) as well as Service Data Objects into and out of Ruby components. Service Data Objects are represented in Ruby as REXML Document objects (see the Ruby BigBank sample for a demonstration).

You can write a componentType file for your Ruby component, but you don't have to - the Ruby extension introspects Ruby component implementation classes for you and binds public attributes to references and properties.

References

References can be invoked from Ruby component implementations by the use of public attributes in the component implementation classes, like this:

class CalculatorImpl

  # Define the public attribute that corresponds to the divideService reference
  attr_writer :divideService

...	

  def div(arg1, arg2)
    print "Ruby - CalculatorImpl.div\n"
    # Invoke the divideService reference
    @divideService.divide(arg1.to_f, arg2.to_f)
  end

...
end

and in your composite file:

<component name="CalculatorComponent">
    <implementation.ruby script="CalculatorImpl.rb"/>
    <reference name="divideService">DivideComponent/DivideService</reference>
</component>

Properties

A composite with a property defined for a component like so:

<component name="DivideComponent">
    <implementation.ruby script="DivideImpl.rb" class="DivideImpl"/>
    <property name="round">true</property>
</component>

allows a public attribute of a Ruby component implementation class to be assigned the property value, so it can be used like so:

class DivideImpl

  # Define the public attribute that corresponds to the round property
  attr_writer :round           

...	

  def divide(arg1, arg2)
    print "Ruby - DivideImpl.divide ", arg1, " / ", arg2, "\n"
    res = arg1.to_f / arg2.to_f
    # Use the round property
    if @round then
      res = res.round
      print "DivideImpl.divide rounding\n"
    end
    print "DivideImpl.divide ", res, "\n"
    res
  end
end

Getting Help

First place to look is at the Tuscany FAQ at http://incubator.apache.org/tuscany/faq.html

Any problem with this release can be reported to the Tuscany mailing lists or create a JIRA issue at http://issues.apache.org/jira/browse/Tuscany.