NWRFC - Wrapper for SAP Netweaver RFC SDK using Ruby-FFI
This library provides a wrapper around the sapnwrfc shared library provided in the SAP Netweaver RFC SDK using Ruby-FFI.
The NW RFC SDK allows you to call remote-enabled function modules on an ABAP server (referred to as RFC, which stands for "Remote Function Call").
To use this library, you must have the nwrfcsdk (libsapnwrfc.so / sapnwrfc.dll) library and related libraries somewhere in your path.
I am developing the library using the 7.20 patch level 2 version of the NW RFC SDK. I have used 7.11, but found for instance that it suffers from the bug described in note 1058327, where RfcGetStringLength() returns the incorrect length of the string if it is longer than 255 characters (supposed to have been fixed in 7.10 patch 2).
Issues
Ruby-FFI does not seem to be able to take string encoding into consideration, so for example, calling RfcGetVersion() is problematic, because the returned string pointer has (like all NW RFC SDK functions) UTF-16LE encoding, and FFI does not seem to be able to work with this. So far this is not too problematic, but let's see.
Obtaining the Netweaver RFC shared library
The Netweaver RFC SDK libraries are available from SAP. You cannot, unfortunately, obtain these as a public user; you need to have access via a customer account to download them from SAP Service Marketplace (http://service.sap.com)
Alternatively, you can download and install one of the Netweaver Trial Editions from SDN (requires signup): http://www.sdn.sap.com/irj/scn/downloads
After installation, the files are available in /usr/sap/
Usage
Connecting to the SAP system:
require 'rubygems'
gem 'nwrfc-aphid'
require 'nwrfc'
include NWRFC
c = Connection.new {"user" => "martin", "passwd" => "secret",
"client" => "100", "ashost" => "ajax.domain.com", "sysnr" => "00"}
Calling a function:
f = c.get_function("STFC_STRUCTURE") #Obtain description of a function module
f.with_function_call do |fc|
fc.invoke
end
Or close the function call explicitly. Closing it also releases all nested table and structure data:
fc = f.get_function_call
begin
fc.invoke
ensure
fc.close
end
Function descriptions fetched through a connection are cached and borrowed from the SDK, so f.close
never destroys them. A locally defined function owns its description and should be closed after all calls
created from it have been closed:
local_function = Function.new("MY_FUNCTION")
begin
# add parameters and use local_function
ensure
local_function.close
end
Transactions retain their handle when submit or confirm fails so commit can retry the appropriate step.
Close an abandoned transaction explicitly; close and destroy are idempotent:
transaction = c.start_transaction
begin
fc.invoke(transaction)
transaction.commit
ensure
transaction.close
end
Connections and servers also have idempotent close methods. Function calls received by server callbacks,
and table or structure handles obtained from a function call, are borrowed and are never destroyed directly.
Setting and getting parameters and fields:
import_struc = fc[:IMPORTSTRUC]
import_struc[:RFCCHAR1] = 'a'
Close function calls before their connection:
fc.close
c.close
Installation
In order to install and run nwrfc-aphid, you need to install Ruby-FFI which may require compilation. On Windows, you should be running the one-click Ruby Installer and install the DevKit which is really the easiest way to compile it on Windows.
Then install the nwrfc-aphid gem:
In a Bundler Gemfile:
gem 'nwrfc-aphid', require: 'nwrfc'
On Linux:
sudo gem install nwrfc-aphid
On Windows
gem install nwrfc-aphid
Documentation
Documentation is installed locally when you install the gem, but you can install it with rdoc or yard or whatever
if you have cloned the repository from GitHub.
Running the tests
The test are located in the tests/ directory. The file login_params.yaml contains parameters that you will need
to customize to log on to your local system that you are testing with. The YAML file contains parameters for multiple
systems, so if you want to switch to a different system, change the following line in test_nwrfc.rb:
$login_params = YAML.load_file(File.dirname(__FILE__) + "/login_params.yaml")["system2"]
so that ["system2"] at the end points to whatever label you gave it in the YAML file, then
rake test
Release Notes
Available in 0.1.0 (nwrfc-aphid)
- Maintained fork packaged as nwrfc-aphid
- Ruby 4 and Bundler 4 dependency compatibility
Available in 0.0.9
- Support for qRFC/tRFC
Available in 0.0.8
- BigDecimal support added for BCD values (BCD is also returned as BigDecimal to cater for very big numbers like timestamps)
- Support for String::encode in Ruby 1.9 and above instead of iconv (thanks Meatballs1)
What's new in 0.0.7
- Add support for JRuby by extending FFI::StructLayout::CharArrayProxy
- Fix #7 (error when reading timestamp value / BCD field)
What's new in 0.0.6
- Add :blocking => true in attach_function to allow other threads to continue running (thanks Meatballs1)
What's new in 0.0.5
- Bug fix for Table#each
What's new in 0.0.4
- Add parameter activation/deactivation functionality
- Fix/add metadata retrieval for DataContainer
What's new in 0.0.3
- Basic RFC server functionality
What's new in 0.0.2
- More comprehensive type support
- More table operations
What's new in 0.0.1
- Fix loading sapnw library
- Fix UTF-8 conversion for Windows
- Enhanced type support
What's new in 0.0.0
- Able to call functions
- Most types work,
- Getting list of fields from a structure causes a SEGFAULT
Contributing
- Improvements to the source code are welcome
- Indicate on which platforms you have tested the gem
- Suggestions for improving the API / Hints for idiomatic Ruby