Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

When I first started trying to interface to an SAP system with perl, I was not very adept at perl coding.  Sure, I had written several scripts in the prior 5 years or so, but I did it so infrequently that I forgot most of what I had learned about arrays, hashes, and other such constructs.  Add to that the fact that I was not in the habit of commenting my code, and I not only had to learn how to code new logic, I also had to re-learn how to write what I'd already written!

To add to my challenge, I was not very well-rounded at ABAP.  I had spent time modifying programs, troubleshooting, performance tuning database accesses, etc, but I had never worked on a program that was intended to be called by other programs, as is the case with an RFC-enabled function module.  So I had a bit of learning to do there as well, such as how to determine what type of input a function module was expecting, what type of output it would provide, and how to test the program.  Perhaps it's good that I'm finally writing all this down.  Maybe next time I need to write a script, I'll just come here first.

So the first thing you need to do to make an RFC call to an SAP system from a perl script is to ensure you've got the proper configuration on your scripting host (see Perl and SAP Adventures, Part 1 of this blog).

Secondly, you must identify an RFC-enabled function module in your SAP system to execute for whatever it is you wish to accomplish there. This blog will attempt to walk through this second step for those that are as unfamiliar with some of this as I was when I first started.

To find RFC-enabled function modules, go to transaction SE37. Click Utilities -> Find. Then, Edit -> All Selections. You can then click the "RFC Modules" radio button under the "Additional Selections" section. Next, put some text into the Function Module name or Short Description fields (note that many do not have a short description), and click the execute button, or hit F8. You will want to use some text here to limit the search, as there are over 30,000 RFC-enabled function modules in my ECC 6.0 system, for example.

Once you have found a function module that piques your interest, double-click on it to display the code.

I'm going to pick a simple one to start with, which is TH_SERVER_LIST. This function module will list all of the servers in the system. Looking at the code for this function module, the header is as follows:

FUNCTION TH_SERVER_LIST.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"  IMPORTING
*"     VALUE(SERVICES) LIKE  MSXXLIST-MSGTYPES DEFAULT 255
*"     VALUE(SYSSERVICE) TYPE  MSSYSSERVICE DEFAULT 0
*"  TABLES
*"      LIST STRUCTURE  MSXXLIST OPTIONAL
*"      LIST_IPV6 STRUCTURE  MSXXLIST_V6 OPTIONAL
*"  EXCEPTIONS
*"      NO_SERVER_LIST
*"----------------------------------------------------------------------
What I'm concerned with first are the IMPORTING parameters. This tells you what parameters you need to pass to the function module when your script calls it. In this case, each of the import parameters has a default value, and so is not required to be passed in from the script, unless you want to override the default.

Second, you want to look at what data the function module can provide for you, either via EXPORTING values (there is no exporting section in the header of this function module, so it has no exporting values), or via TABLES. In this case, a structure (which is essentially a memory-resident table) called LIST is provided by this function module. The LIST structure is of type MSXXLIST. To find out what LIST provides, you can double click on the word MSXXLIST, which will display for you the following structure definition (similar to what you would see if you looked up a table in the ABAP data dictionary from SE11):
Component   Component Type   Data Type   Length   Decimal Pl   Short Description
NAME        MSNAME2          CHAR        40       0            Application Server Name
HOST        MSHOST2          CHAR        32       0            Name of Application Server
SERV        MSSERV           CHAR        20       0            Service
MSGTYPES    MSTYPES          RAW          1       0            Services
HOSTADR     MSHOSTADR        RAW          4       0            Host IP address
SERVNO      MSSERVNO         RAW          2       0            Service port number
STATE       MSSTATE          RAW          1       0            Server Status
Now, the first thing to do from here is to see this function module in action to verify it's what you need before you go writing lots of code.  To do this, if you're looking at the code of the function module, you can click on the Test button, which looks a bit like the Winzip icon, or simply press the F8 key. This will give you a screen with the input parameters as fields you can enter values into. With this function module, you don't need to input any parameters, so simply hit the Execute button or, again, press F8. This will execute the script and provide a screen with the output. Clicking on the LIST structure will show the contents of this table.  It will look something like this (there are a few more columns than this, but you get the idea - oh yeah, and server names have been changed to protect the innocent):
Name                   Host              Serv
apsrv002_RQA_00        apsrv002          sapdp00
apsrv019_RQA_00        apsrv019          sapdp00
apsrv235_RQA_00        apsrv235          sapdp00
apsrv720_RQA_00        apsrv720          sapdp00
apsrv721_RQA_00        apsrv721          sapdp00
apsrv722_RQA_00        apsrv722          sapdp00
apsrv723_RQA_00        apsrv723          sapdp00
apsrv724_RQA_00        apsrv724          sapdp00

In my case, my script would like to grab the NAME of each application server, and I can see that the LIST structure provides that, so I can proceed.

An ABAP structure is made available to a perl script as an array of hashes. An array is a list of items, and a hash is a series of key/value pairs. So each item in the array will be a hash, and the keys for each hash will match up with the fields (components) in the structure above. Conceptually, it will look something like this:
@LIST=(
hash1 {'NAME' => 'apsrv002_RQA_00', 'HOST' => 'apsrv002', 'SERV' => 'sapdp00', ...}
hash2 {'NAME' => 'apsrv019_RQA_00', 'HOST' => 'apsrv019', 'SERV' => 'sapdp00', ...}
hash3 {'NAME' => 'apsrv235_RQA_00', 'HOST' => 'apsrv235', 'SERV' => 'sapdp00', ...}
)

Therefore, to get the name of each application server in the system, the script would need to loop through the hashes in the LIST array, and get the value associated with the NAME key from each hash. This will look something like this (this is short, but it is a complete working script):

#!/usr/bin/perl -w
use strict;
use sapnwrfc;                                              # here's where we load the SAPNW::Rfc module
SAPNW::Rfc->load_config;                                   # load the connection parameters defined in sap.yml
my $rfc = SAPNW::Rfc->rfc_connect;                         # connect to SAP system
my $rcb = $rfc->function_lookup("TH_SERVER_LIST");         # look up the function module
my $tsl = $rcb->create_function_call;                      # create the function call
$tsl->invoke;                                              # execute the function call
foreach my $row (@{$tsl->LIST}) {                          # now loop through each of the rows in the LIST array
   print "Server is $row->{'NAME'}
";                     # and print the server NAME value for each
}
$rfc->disconnect();                                        # disconnect from the system
The output this will give us when executed is:
[dhull@localhost #]$ ./blog.pl
Server is apsrv002_RQA_00                        
Server is apsrv019_RQA_00                        
Server is apsrv235_RQA_00                        
Server is apsrv720_RQA_00                        
Server is apsrv721_RQA_00                        
Server is apsrv722_RQA_00                        
Server is apsrv723_RQA_00                        
Server is apsrv724_RQA_00                        

And there you have it - a completed script!

In the Perl and SAP Adventures, Part 3, I'll expand on this script by taking these server names and doing something with them.

1 Comment