« October 2005 | Main | December 2005 »

November 20, 2005

SAP and Open Source: an analysis and letter to SAP and Shai

DJ writes a very good analysis of what most people DIDN'T understand about what Shai Agassi said at a recent "Churchill Club" shmooze, on SAP's future plans regarding closing SAP's very successful Open Source strategy .....

Posted by PiersHarding at 4:56 PM

November 17, 2005

Interfacing data into BW using Perl, Ruby, or Python

I've just completed the first SAP related course that I've been on for many years - BW310 - in London, Clockhouse Place. Surprisingly, I have really enjoyed it, and the lecturer has been excellent (my thanks go to Gurjeet Dosanjh).

On the back this, and other fiddling with the Business Warehouse, I've had a look at loading data in "push" mode, and have struck yet another great use for RFC support available in scripting languages. With the unrivaled abilities of scripting languages to munging, mash, and manipulate any kind of data, coupled with the automatically generated RFC interface (DataSource) attached to an InfoSource within BW, the job is trivial.

The RFC DataSource piggy-backs on the BW <-> XI SOAP interface that is generated when you go to edit your InfoSource in the AWB (transaction RSA1). This is accessed by selecting the Extras menu, and then choosing "Create BW DataSource with SOAP Connection".

image Edit InfoSource view - automatically generating the SOAP RFC connector

This is discussed in detail on help.sap.com at this page You must pay carefull attention to the details surrounding "Creating XML DataSources" and "Activating Data Transfer to the Delta Queue". You can check if you have this right by looking at transaction RSA7 - BW Delta Queue Maintenance, and making sure the traffic lights are green.

Once you have activated the RFC interface, you need to determine what the real "technical name is". The technical name for the DataSource that I created for the RFC interface example below is 6AZODSINFOXX (as viewed in RSA7) - this translates to an RFC name of /BI0/QI6AZODSINFOXX_RFC - just open yours up in SE37 for the details.

The following example is written in Ruby, however, the language bindings exist for RFC for Ruby, Perl, and Python, so - please - choose what you fancy - you can find out more about them all at here or look at previous articles that I have written here.

Here is a basic step through of what it takes to get the data loading scenario going:

require "SAP/Rfc"

# connect
rfc = SAP::Rfc.new(:ashost => "seahorse.local.net",
                   :sysnr  => 00,
                   :lang   => "EN",
                   :client => "010",
                   :user   => "developer",
                   :passwd => "developer",
                   :trace  => 1)

# lookup the BW RFC interface
i = rfc.discover("/BI0/QI6AZODSINFOXX_RFC")

# set the datasource to connect to
i.datasource.value = "6AZODSINFOXX"

# grab the structure of the transfer structure
str = i.data.structure

# start processing the input file - doesnt have to be a file  though
fh = File.open("./data1.csv")
i.data.value = []

fh.each { |line|
  # drop the first line
  next if fh.lineno == 1

  # remove the line end

  # split the columns on ","
  flds = line.split(",")

  # remove any quotes around column values
  flds.each {|f| f.sub!(/^\"(.*?)\"$/, '\1') }

  # fillout the BW transfer structure
  str.getField("RECORDMODE").value = flds[0]
  str.getField("/BIC/ZEQUIP_XX").value = flds[1]
  str.getField("/BIC/ZNAME_XX").value = flds[2]

  # add the row to the table

# call and test the return

# basic error checking of the inserted record batch - check the exception thrown, if any
print "Error is: #{i.error}\n"

In this example I have just used a typical CSV input file as displayed below to provide input data - but you can use your imagination here - it could be MySQL, a POE server, your legacy AS400 system - it's up to you :-) File:

,0000009011,"CONTROLS FAILED - 3"
,0000009012,"VALVE LEAK - 3"
,0000009013,"OIL LEAK - 3"
,0000009014,"NUT WIBBLED - 3"
,0000009012,"TYRE WOBBLES - 3"
,0000009011,"NUT FAILURE - 3"

Enjoy! :-)

Posted by PiersHarding at 7:15 AM

November 15, 2005

Write your own RFCs without using SE37!

Of late - I have found a need to be able to write RFCs on the fly - partly to be able to deliver new functionality to my user base for my RFC implementations for Perl, Python, and Ruby. Using transports is not an option because of potential licensing issues, and the practicalities of release support. I started looking into how you can actually write Function Modules on the fly, and ended up with SAP::Tools which I have first released for Ruby.

Here is an example (albeit a pointless one) of how to build up an interface, and then insert the code into an RFC that is ready to run.

require "lib/SAP/Tools"

rfc = SAP::Tools.new(:ashost => "seahorse.local.net",
                   :sysnr  => 00,
                   :lang   => "EN",
                   :client => 000,
                   :user   => "DEVELOPER",
                   :passwd => "DEVELOPER",
                   :trace  => 1)

func_pool = "ZMYRFC1"
func = "ZTEST"
short_text = "Some function group - #{func_pool}"
func_desc = "description of #{func}"

# get the connection ID
print "[main] connect id: ", rfc.connection, "\n"

# test the connection
print "[main] is_connected: ", rfc.is_connected(), "\n"

if rfc.existsRFC(func)
  print "[main] deleting: #{func}\n"

ztest = SAP::Iface.new(func)
ztest.addParm(SAP::Parm.new(:name => "PARMIMP", :type => RFCIMPORT, :like => "SY-REPID", :optional => true))
ztest.addParm(SAP::Parm.new(:name => "PARMEXP", :type => RFCEXPORT, :like => "TRDIR"))
ztest.addParm(SAP::Parm.new(:name => "SYSTEM", :type => RFCEXPORT, :like => "SY-SYSID"))
ztest.addParm(SAP::Tab.new(:name => "WAHOO", :like => "TAB512", :optional => true))

src =  [
      'TABLES: TRDIR.',
      'SYSTEM = SY-SYSID.',
      'PARMEXP = TRDIR.',

test = rfc.makeRFC(:func => ztest,
                    :desc => func_desc,
                    :group => func_pool,
                    :grouptext => short_text,
                    :source => src)

# close the connection
print "[main] close connection: ", rfc.close(), "\n"

You may ask why would I bother to go to this trouble, and my reply is that I have been banging my head against SAP's inertia, and internal politics for the last year, trying to get access to the new features for handling complex data types in RFC . As a result I have had to build a complex framework for automatically generating RFC to support my efforts for dynamically instantiating ABAP Objects, and calling methods etc. from Perl, Ruby etc.

However - a side effect is that this can open up the way for accessing lots of Function Modules that aren't RFC enabled without having to go to the trouble of developing wrappers from within R/3 (these wrappers can be automatically created for you).

If you think this is a "Hack" then you're right - but as I've eluded to before - this is a Hackers (an artistic programmer as opposed to an nefarious evil-doer) response to the reluctance I have experienced from SAP, in the pursuit of extending the sophistication of integration of R/3 with scripting programming languages from the Open Source world. Further to this - I am noticing a worrying trend in Senior SAP Executive rhetoric with respect to Open Source, and am wondering if this is signalling a change in some of the founding principles that have carried SAP to such heights as it enjoys now.

Posted by PiersHarding at 8:03 AM | Comments (2)

November 13, 2005

Win32 gem file available for Ruby saprfc 0.11

Olivier has done it again - Olivier is my generous win32 porter for Perl and SAP::Rfc, and now he has made SAP::Rfc for Ruby available too, as a gem package. the Ruby gem is available for download from here.
Remember - when you are using gems - instead of the 'require saprfc' to pull in the SAP::Rfc library you must use:

require 'rubygems'
require_gem "saprfc"
rfc = SAP::Rfc.new(...)

This opens SAP::Rfc up to all those windows users who have contacted me over the last year.

Thanks Olivier!

Posted by PiersHarding at 6:49 AM