RFC - Perl extension for SAP remote function call
use RFC;
print RFC::lastError();
$abap = RFC::p2a("Perl");
$perl = RFC::a2p("ABAP");
$conn = RFC->connect($sys, $client, $user, $pass);
$func = RFC->function($name, \%in, \%out, \%tables);
$rec = RFC->struct("Name", "First" => RFC->type('C', 32),
"Last" => RFC->type('C', 32),
"Age" => RFC->type('I', 4));
The RFC package is an object oriented interface to the Remote Function Call API provided by SAP.
The Remote Function Call API (RFC API) allows calling ABAP/4 function modules from C programs as well as receiving call requests issued from an ABAP/4 program by the CALL FUNCTION interface.
In ABAP/4, function modules are special routines with well defined and documented interfaces, which are developed within a library development workbench.
ABAP/4 function modules use named parameter passing. Also there are exceptions which can be raised by a function module to indicate errors. The exceptions can be caught by the caller of a function module.
What this means is, that all the functionality a SAP R/3 system makes accessible for external programs is now at the fingertips of the perl programmer.
Perl must be at least version 5.004.
You'll need the RFC source development kit for your operating system. Make sure you have at least the version that comes with R/3 release 30C. The RFC SDK is provided by SAP and is not (and, for legal reasons, cannot be) part of this distribution. Sorry.
However, you'll find a collection of RFC SDK's for all operating systems supported by SAP on the CD labelled ``Presentation CD'' that is part of every R/3 distribution.
In addition, there is now also a linux version for download from the sapservX servers. Normally, you can access those servers only if you own a R/3 licence.
The package was developed on a LINUX system with kernel version 2.0.36.
It was tested on AIX 3.2.5 and AIX 4.3.2 (so any AIX version should do) and on Windows NT 4.0 with a native perl.
It should work on any UNIX as well as on Windows95/98. If not, please let me know.
All subroutine and method names provided by this library start with a lowercase letter. All class names start with an uppercase letter.
Contstant names from the RFC library are in all uppercase letters. The leading ``RFC_'' is omitted. Since the RFC package exports nothing, even constant names must be prefixed by ``RFC::''. For example, in C you'd write
RFC_OK ITAB_NULL
In perl, write
RFC::OK RFC::ITAB_NULL
When programming RFC applications, one has to deal a lot with names defined in the R/3 data dictionary or in ABAP. In particular, these are names of tables, structures, fields, functions and parameters.
ABAP names consist of all uppercase letters with embedded
underscores like THIS_IS_UGLY, UPPERCASE_SUCKS and
so on. Since in perl, by convention, uppercase names
indicate constants or special perl internal variables this
package will convert ABAP names in an intuitive manner that would
result in ThisIsUgly, UppercaseSucks and so on.
The bottom line is that you should always use the perl form of any name that comes from the R/3 data dictionary.
At any time you can see what the perl name for a given ABAP name (or vice versa) would be by running one of the following commands:
perl -MRFC -e 'print RFC::a2p("ABAP_NAME"), "\n";'
perl -MRFC -e 'print RFC::p2a("PerlName"), "\n";'
You'll normally never see this return code since exception handling takes place in the library code that deals with function calls.
You'll normally never see this return code since exception handling takes place in the library code that deals with function calls.
With this extension for SAP remote function calls, a perl program may act as a RFC server or a RFC client.
A RFC server is a program that registers at a R/3 system under a unique program name and waits for function call requests from R/3.
A RFC client is a program that connects to a R/3 system and requests execution of certain functions.
A connection to R/3 is represented by an object of class RFC::Conn.
A RFC client can call a function in a R/3 system. A RFC server executes functions that are called by some ABAP code in the R/3.
In both cases, the functions (or function modules) must be known to the R/3 system, i.e. they must be described in the data dictionary of the R/3 system.
The perl extension for RFC described here provides a way to describe the interface a function module has through the RFC::Func class.
In a perl RFC program, RFC::Func-objects are being used to
ABAP programs work with data objects that have a certain type. The scalar types known in ABAP are fixed length character strings, fixed length character strings with digits only (they call it numeric, but you must not do arithmetic with it), dates, times, integers, fixed length binary strings, float and packed decimals.
In addition, they have so-called internal tables, a replacement for arrays, but with a more database-like set of operations. Consequently, the elements of those tables are not scalar values, but records or structures. Structures are made up of a number of fields, each having a name and a (scalar) data type. Structure layouts are defined under an unique name in the data dictionary.
This package maps scalar perl values to scalar ABAP types and back
whenever this is needed. To do this, we have to know the exact
ABAP type. For example, it makes a great difference if we convert the
perl value "123"
a) to a character string with length 5, which gives ``123 '',
b) or to a numeric string with length 5, which gives ``00123'',
c) or to a packed decimal with 5 digits and precision 2, which gives ``\x12\x30\x0c'',
d) or to a 2 byte integer, which gives ``\x00\x7b''.
Classes derived from RFC::Type handle all conversion tasks.
Structures will be mapped to objects of a structure class that is
derived from RFC::S, the mother of all structures.
Definition of a structure is as easy as listing the field
names and their types. Individual field values can then be accessed
and set by field name.
Support for internal tables is very straightforward.
Besides table creation and destruction, there is only one method
to append a row to a given table and one to return the whole contents
of the table as a perl array. This is implemented in RFC::ITab.
use RFC;
$conn = RFC::Conn->client($sys, $client, $user, $pass); # create client connection $conn = RFC->connect($sys, $client, $user, $pass); # same, but shorter
$conn = RFC::Conn->server(@ARGV); # create server connection $conn = RFC->accept(@ARGV); # same, but shorter
$conn->close;
print $conn->handle;
The RFC::Conn class maintains connections to R/3 systems.
undef on failure.
Instead of this, the following shorthand can also be used:
RFC->connect($sys, $mantd, $user, $pass);
The arguments have the following meaning:
RFC_CLIENT will be used. If this is also undefined, "000" will
be used.
RFC_USER
will be used. If this is also undefined and the standard input is a
terminal the user will be prompted for the user name. If all fails,
the default "SAPCPIC" will be used.
RFC_PASS
will be used. If this is also undefined and the standard input is a
terminal the user will be prompted for the pasword. If all fails,
a default of "ICECREAM" will be used.
"-aprogid", "-ggwhost", "-xgwserv", "-t")"-Ddestination")server(@ARGV)The first form registers an RFC server under the identification
progid at a SAP gateway that runs on gwhost on port gwserv.
The -t flag may be omitted. If present, a trace will be written
to some trace file.
gwhost must be a valid hostname.
gwserv must be a valid servicename, usually somthing like
sapgw00
The second form uses the parameters customized in the saprfc.ini
file under the destination name destination. The destination
type must be R.
The connection may then be used through a RFC destination with the same progid. Note that progid is case sensitive.
You may register more than one program under the same progid. The SAP gateway will use the second connection on a request for progid when the first connection is busy. If the second connection is also busy, it will try the third one, and so on.
It is even possible to register multiple programs from different machines under the same progid.
The 3rd form is used when the SAP gateway calls your program directly or through some remote shell mechanism. In this case, the gateway itself passes some (6) arguments on the command line. This information makes it possible to establish a TCP/IP connection with the SAP gateway.
How do you know if the gateway is going to call your program directly or if it is expecting a registered program? It depends on the RFC destination used by your ABAP program. The ABAP program only knows the name of the RFC destination. How the establishment of the connection actually works is a matter of customizing the RFC destination.
This raises the question of what is ``better'': explicit call or registered program?
With explicit call your RFC server program is a subprocess of the SAP gateway. It runs with the user id of the SAP gateway (usually the SAP administration user). The program starts out in some directory in the SAP directory tree (/usr/sap/<SID>/D*/work) and it has the same set of environment variables like the gateway itself. Even worse if the program must run on a different machine: The SAP gateway will then use some remote shell mechanism to execute your program on that machine.
This, of course, makes explicit calls very dangerous in terms of computer security. Utilization of remote shell mechanisms should be a taboo in a secure environment. But local execution of a program under the user id of the SAP administrator is not much better: The program could kill any SAP processes, remove or replace any files of the SAP system and it could do severe damage to the R/3 database.
In comparision, a registered program can run on any machine that is able to make a TCPIP connection to the host where the SAP gateway runs. It can run with any user id. This way, it is possible to protect your SAP system from any damage while still allowing RFC server programs.
Registered RFC servers may also perform better than explicitely called ones. This is so because they are only started once after the start of the R/3 system and from then on can serve an unlimited number of requests.
Note that you can write server programs that can handle any invocation methods. Just say
$server = RFC->accept(@ARGV);
This program will work when it is called directly by the gateway. It also works when you call it like this:
server.pl -aprogid -xsapgw05 -gr3machine.big.com
or with a preconfigured destination in some saprfc.ini file:
RFC_INI=~dieter/config/r3.ini server.pl -DPRODREG
The form using the saprfc.ini file is most recommended.
RFC::HANDLE_NULL.
RFC_SYSTEM_INFO.
Depending on the byte order, which is either "BIG" or "LIT",
arranges for proper interpretation of integer values in structures.
See also Integer and float types in structures.
The return value is "BIG" or "LIT" if the function call was
successful. Otherwise, a false value is returned.
RFC_SYSTEM_INFO and returns it.
Returns false if the function call was not successful.
RFC_SYSTEM_INFO is called only once per RFC::Conn object and
the result is cached,
no matter if the endian or the saprelease
method was called.
$func = RFC::Func->new($name, \%in, \%out, \%tables); $func = RFC->function($name, \%in, \%out, \%tables); # same as above
$func = RFC->function("ZTestFunc", # Z_TEST_FUNC
{ "Param" => RFC->type('C', 5), },
{ "Result" => RFC->type('C', 16), },
{ "MyTable" => RFC->table(...), });
$func->Param("value"); # set value for input parameter
$func->MyTable->create; # provide empty table parameter
$func->call($conn); # where $conn->isa("RFC::conn")
print $func->Result; # access output parameters
The RFC::Func class maintains function objects.
Essentially, function objects hold parameter descriptions
and provide access to the parameter values itself.
$name is the name of
the function as defined in the R/3 data dictionary. The three hashes
%in, %out and %tables describe the input, output
and table parameters. The keys of those hashes are the parameter or
table names.
The values are the types of the parameters or table rows.
(see TYPES and RFC::Type
for a discussion of types.)
Example
Suppose we had called
$tab512 = RFC->struct("Tab512",
"Rowdata" => RFC->type('C', 512));
$func = RFC->function("RfcGetTableEntries",
# in
{
"MaxEntries" => RFC->type('I', 4),
"TableName" => RFC->type('C', 30),
},
# out
{
"NumberOfEntries" => RFC->type('I', 4),
},
# tables
{
"Entries" => $tab512
};
This describes a function that takes two arguments. The first
argument, MaxEntries, is an integer. The other argument,
TableName is a character string with a maximum length of 30 bytes.
The function returns an integer, NumberOfEntries and does
something with an internal table that has rows of type Tab512.
Tab512 is a structure type with just one field, Rowdata.
Once this declaration is done, we could set some input parameter values:
$func->MaxEntries(7);
$func->TableName("USR01");
make a fresh internal table with no rows in int:
$func->Entries->create;
and call the function
$func->call($conn); # ref $conn must be RFC::Conn
after that, we could retrieve the value of the output parameter and get the table rows
print $func->name, " returned ", $func->NumberOfEntries, " rows.\n";
foreach ($func->Entries->get) {
# do something with $_, which is a reference
# to a "Tab512" object.
$username = substr($_->Rowdata, 0, 8);
}
call($conn)Returns a boolean value that indicates if the function call succeeded. Note that this does not mean, that the ABAP function was successful. For example, BAPI functions usually return a structure that contains information regarding success or failure.
If the ABAP function raises an exception that is part of its interface, a
die "$exception_name\n";
will be done.
It may also happen that the R/3 system itself decides to raise an
exception. This is true for example, when the function name is unknown
in the R/3 system or if the RFC user is not allowed to execute
the function. In this case, $func->call also dies.
The recommended idiom for a call is thus:
if (eval { $func->call($conn) }) {
# success
...
}
elsif ($@ eq "EXCEPTION_I_CAN_HANDLE\n") {
# expected exception
...
}
elsif ($@) {
# unexpected exception
confess "unexpected exception $@";
}
else {
# RFC error
print STDERR "Couldn't call, due to ", RFC::lastError(), "\n";
...
};
Scalar parameter values can be set with the second form.
This class and it's subclasses handle all the conversions between ABAP and perl values.
$tchr = RFC->type('C', 5); # alphanumeric, length 5
$tnum = RFC->type('N', 7); # numeric string, length 7
$thex = RFC->type('X', 2); # binary string, length 2
$tbcd = RFC->type('P', 3, 2); # a packed number of length 3
# (5 digits) and two decimals positions
$tint = RFC->type('I', 4); # integer, length 4
$tfld = RFC->type('i', 2); # a short in a structure
$tdate = RFC->type('D'); # a date (e.g. "19992203")
$ttime = RFC->type('T'); # a time (e.g. "202905")
$tfloat = RFC->type('F'); # a C double.
print $tchr->bytes; # 5
print $tint->default; # 0
print $tbcd->decimals; # 2
print $tnum->aval("34"); # "0000034"
print $tchr->pval("abc "); # "abc"
RFC::Type is the base class of all classes resembling ABAP types
used in your program. The call to RFC->type either derives a
new type class from RFC::Type on the fly
and returns the name of that
class (which happens to be something like RFC::Type::CLen5Dec0) or
it returns the name of a previously defined class.
The type classes are mostly used internally. You just say of what type a parameter or field is, the rest is done automatically.
All classes derived from RFC::Type have the following class methods:
P).
RFC::TYPC for character types, RFC::TYPDATE for the date
type, RFC::TYPTIME for the time type, RFC::TYPP for packed types,
RFC::TYPX for binary string types, RFC::TYPNUM for numeric string
types, RFC::TYPFLOAT for the float type, RFC::TYPINT for the
4 bytes ineger types, RFC::TYPINT2 for the 2 byte integer types or
RFC::TYPINT1 for the single byte integer type.
Type Description Bytes (min..max) Default value
C character string 1..unlimited all blanks
N numeric string 1..unlimited all "0"
X binary string 1..unlimited all hexadecimal 0
P packed decimal 1..16, decimal packed 0
0..14 decimals
D date (YYYYMMDD) 8 "00000000"
T time (HHMMSS) 6 "000000"
F floating point 8 pack('d', 0.0)
I integer 4, 2 or 1 0 (local endian)
i integer 4 or 2 0 (remote endian)
Please note that RFC->type always expects the length in
bytes as the second argument. A packed decimal with N bytes stores
2*N-1 decimal digits and a sign.
This class provides the base for the implementation of structure types.
# declare a structure
$styp = RFC->struct("MyStruct",
"Name" => RFC->type('C', 30),
"Income" => RFC->type('P', 10, 2),
# .... as many fields as you want
);
$sobj = $styp->new; # make a MyStruct object $other = $sobj->new; # make an object with same type as $sobj
$sobj->Name("Ingo"); # set field value
$notmuch = $sobj->Income; # get field value
print $sobj->field("Name"); # another way to get a field value
$sobj->field("Income", 0); # another way to set a field value
@flds = $styp->fields; # return field names (in random order)
@flds = $styp->ordered; # return field names ordered by offset
$ftyp = $styp->types; # return field info {fname => type, ...}
$foff = $styp->offsets; # return field info {fname => offset, ...}
$sdef = $styp->default; # default ABAP value print $styp->bytes; # how many bytes is the struct $aval = RFC::S->aval($sobj); # return the structure as string $obj3 = $styp->pval($aval); # make an object of type $styp from string
The call RFC->struct creates a new structure type. The first
argument must be the structure name. If the structure name contains no
::, it will be prepended with RFC::S::.
The (eventually modified) structure name will then be used as a
package name and a new class will be derived from RFC::S in that
package. Finally, the package name is returned so it can be used
as a type name in further calls.
The new class inherits all class methods from RFC::S (see below).
In addition, for each field in the field list, a set/get method will
be created. Field names should not start with lowercase letters or
they should contain at least a digit, uppercase letter or underscore to
avoid name clashes with predefined methods.
RFC::S itself is derived from
RFC::Type and therefore inherits
the RFC::Type class methods.
bytes()default()typecode()RFC::TYPC (after all, structures are just long strings,
aren't they?)
RFC::S, to a string.
It is not recommended to use this method since it does not guarantee that the fields have proper values.
new()$class->pval($class->default)
fields()ordered()types()If you think of changing the referenced hash, don't.
offsets()If you think of changing the referenced hash, don't.
This method is of great value in conjunction with fields,
ordered, types and offsets. For example, the following
subroutine prints all non empty strings from any structure:
sub pnecf($) {
my $s = shift;
my %h = $s->types;
foreach ($s->ordered) {
# we assume that structures are not nested.
next unless $h{$_}->typecode == RFC::TYPC;
next unless length $s->field($_);
print "$_ = '", $s->field($_), "'\n";
}
}
Note that structures cannot be nested.
aval()(ref $obj)->aval($obj).
In other words, aval() on an object returns the structure data
of this object. This is a string in the length of the structure.
pval()(ref $obj)->pval($obj->aval).
In other words, pval() creates a new object with a copy of the
data of the original object.
Note that a copy of an object is very different from the copy of just an object reference:
RFC->Struct("Example", "WORD" => RFC->type('C', 3));
my $first = RFC::S::Example->new;
$first->Word("foo");
my $other = $first;
$other->Word("bar");
print $first->Word, "\n"; # prints "bar"
$other = $first->pval();
$other->Word("foo");
print $first->Word, "\n"; # prints still "bar"
The RFC SDK can handle native integers and 8-byte float values as long as they are passed as input or output parameters to or from functions.
However, it can't do that in structures and table rows because it has no idea of how structures are layed out.
That means the types F and I with lengths 2 and 4
can only be used for scalar
parameter values. Using integers and floats in structures or tables
will only work as long as the machine where the R/3 system
is running has the same architecture as the machine where the
RFC program is running.
Fortunately, there is a work around that works in most cases:
i instead I for
integers of length 2 or 4. (One byte integers are never a problem).
$conn->endian
before setting integer fields in your structure(s) or getting such
values from structure(s). This call will find out the way
the R/3 machine stores its integers and arrange that those values
will be converted properly later.
Note that this call may not work on server connections, depending on the RFC SDK version.
If you have multiple connections to different R/3 systems, all is not lost, although the code gets more complicated:
# A structure with an integer field
$s1 = RFC->struct("Struct1",
"Field1" => RFC->type('C', 20),
# ... more fields ...
"Sval" => RFC->type('i', 2),
# ... other fields ...
);
# A function that returns such a structure
$f1 = RFC->function("ReturnS1", { ... }, { "Retval" => $s1 }, {});
# Another structure with an integer field
$s2 = RFC->struct("Struct2",
# ... some fields ...
"Lval" => RFC->type('i', 4),
# ... other fields ...
);
# ... and a function that takes such a structure
$f2 = RFC->function("TakeS2", { "Param1" => $s1 }, { ... }, {});
# two connections to different systems
$conn1 = RFC->connect("S01", ....);
$conn2 = RFC->connect("S02", ....);
...
$f1->call($conn1);
# before we get Sval, determine byte order
$conn1->endian;
#
# If we had only one connection, we could say
# $f2->Param1->Lval($f1->Retval->Sval)
# but since we have 2 connections, we need to do it like this:
#
my $i = $f1->Retval->Sval;
$conn2->endian;
$f2->Param1->Lval($i);
...
$f2->call($conn2);
Note that there is no way to convert float fields between different machine architectures. Sorry. Fortunately, float fields are very seldom used in R/3 structures.
This class implements internal tables.
$struct = RFC->struct(...);
$table = RFC->table($struct); # a table for $struct objects $table->create; # get a table handle
print "Table handle assigned."
unless $table->handle == RFC::ITAB_NULL);
print "The base type is ", $table->base, "\n";
print "There are ", $table->rows, " rows.\n";
$s = $table->getrow($i) # one $struct object
if $i>0 && $i<=$table->rows;
@rows = $table->getrows; # array of $struct objects
$table->append($x) if $x->isa($struct); $table->append($x, $y, @other);
$table->free; # delete all rows, keep table handle $table->delete; # delete all rows and free table handle
The RFC::ITab class is an interface to the
RFCAPI functions that deal with internal tables.
An internal table
is a concept from the ABAP language that is roughly equivalent to
arrays in other languages.
An RFC::ITab object is an indexed collection of structures.
All structures
stored in one table must be of the same type
caled the base type of the table. The base type must be
specified when the table object is created.
The class provides methods to create a table object, assign a table handle, check the number of rows, append rows, get rows and delete rows.
table($structtyp)new($structtyp)$structtyp.
RFC::ITab object.
Should the table already have a handle, this will also free all table
data and destroy the old handle.
This method is mostly used internally. I see no reason why someone would want to call it explicitely.
$table.
If none is assigned, returns RFC::ITAB_NULL.
$table.
getrow($index)$index and returns it as an object of
the appropriate structure class.
$index must be in the range 1..$table->rows, otherwise,
undef is returned.
map { $table->getrow($_); } 1..$table->rows
Be warned, however, that this needs space for (at least) 2*$table->rows rows, since the memory in the internal table is still allocated.
append(@rows)@rows is appended to $table.
@rows must only contain structure objects of the class that
was specified at table creation time.
$table.
You may want to free tables between multiple invokations of the
same function.
$table, but also frees the table handle.
This is - like create - not intended for public use.
print RFC::lastError, "\n" unless $rc == RFC::OK;
Returns a string that describes the last error encountered by the RFCAPI library. This also frees some memory used by the RFCAPI library used to store this message.
print RFC::a2p("ABAP_NAME"), "\n";
Converts the argument, which should be a string consisting of uppercase letters, digits and underscores to a more readable string and returns the result. See also the section on naming conventions.
The example above would print
AbapName
If the argument already looks like a perl name, the argument will be returned without conversion.
print RFC::p2a("PerlName"), "\n";
Converts the argument, which should be a string consisting of letters and digits to a less readable string by inserting underscores before each uppercase letter (except if it is the first character) and then converting all letters to uppercase. The result is returned. See also the section on naming conventions.
The example above would print
PERL_NAME
If the argument already looks like an abap name, the argument will be returned without conversion.
RFC_INI.
export RFC_INI=/usr/local/etc/saprfc.ini # ksh, bash
RFC_INI is
not defined, the path ./saprfc.ini will be used.
Warning! Using this feature is very unsecure, since on a UNIX system anybody can list the environment of any running process. That means, anybody could read your R/3 password!
Ingo Wechsung iw@contexo.com
perl(1).