« September 2006 | Main | November 2006 »

October 31, 2006

Ruby and the SOAP RunTime (SRT) Handler

Following on from my previous post about Ruby, Ruby on Rails, and SAP Web Services Integration - I would like to show how to switch to using the SOAP RunTime (SRT) Handler, which makes available SAP Web Services via Virtual Interfaces.

Steps

Create the SAP Web Service

We need to create a web service that exposes the function modules that were used in the UserAdmin Rails application. To do this - go to transaction SE80, go to the Enterprise Services tab, and create a Virtual Interface of type Funciton Group called Z_USERADMIN. Include into this the function modules:

Activate this, and then create a Web Services definiton - again, using SE80, go to the Enterprise Services tab, and create a Web Services definition called Z_USERADMIN - referencing the previously activated Vitual Interface Z_USERADMIN.
Finally - activate this in the ICF configuration (SICF), by using transaction WSCONFIG, referencing the Web Service definition Z_USERADMIN created above.
There is an excellent discussion of the details of this process by Thomas Jung, here, and here.

Modify model sap_user.rb

Now for the final part - in the UserAdmin Rails application, edit the SapUser model file app/models/sap_user.rb. This needs to switch from referencing the method "function_module" for loading the functions, to using "resources", as outlined below:
require_gem "sap4rails"

class SapUser < SAP4Rails::WS::Base

# You must define a list of RESOURCES to preload
   resources "http://seahorse.local.net:8000/sap/bc/srt/rfc/sap/Z_USERADMIN"
...
Now you can test it as in the previous weblogs.

Unicode!

One thing that I neglected to say in my previous post, is a major advantage of using sapwas for accessing SAP is that it has comprehensive Unicode support - free of charge (but not of pain) :-) .

Round Up

For me - this rounds up SAP Web Services and Ruby - you can either access them in Ruby directly by using the library sapwas, or taking advantage of the Rails integration provided by sap4rails.

Posted by PiersHarding at 11:12 AM

October 23, 2006

sap4rails 0.07 - SAP RFC and auto-reconnect

I released sap4rails 0.07 this week, which corrects a problem with RFC connections not reconnecting correctly (this is using saprfc as the driver - there is no similar issue wtih the sapwas driver, which uses stateless HTTP). This is especially important when the R/3 (ABAP) application server your Rails application is connected to goes down temporarily (or indeed any other temporary communication disturbance). Before an RFC call is executed, the conection is ping checked, and then a single reconnection attempt is tried if the ping fails. If the reconnect fails then an error is raised so it is a good idea to wrap your code in a rescue block, to deal with the situation in your local conditions. Here is an example log:

...
[SapUser] missing_method: Z_BAPI_USER_GETLIST
[SapUser] ifaces: ["SUSR_USER_LOCKSTATE_GET", "BAPI_USER_GET_DETAIL", "BAPI_USER_UNLOCK", "BAPI_USER_LOCK", "Z_BAPI_USER_GETLIST"]
in check connect...
Think Im connected - lets check ...
RFC PING[]...
Something wrong with connection(1) - do it again ...
new connection(2) ...
allready connected ...
[SapUser] missing_method: Z_BAPI_USER_GETLIST
[SapUser] ifaces: ["SUSR_USER_LOCKSTATE_GET", "BAPI_USER_GET_DETAIL", "BAPI_USER_UNLOCK", "BAPI_USER_LOCK", "Z_BAPI_USER_GETLIST"]
in check connect...
Think Im connected - lets check ...
RFC PING[true]...
...

Here you can see the first RFC_PING return nil, and the second after reconnect return [true].

Posted by PiersHarding at 3:05 PM

October 18, 2006

sapwas for Ruby and HTTPS

sapwas for Ruby now enables SAP Web Services to be called via HTTPS. This first requires you to setup SSL support in NW4 - which isn't too much trouble if you follow Gregors' excellent advice here. Once that is in place, then it is just a matter of structuring the URL coorectly, as described in this example:

require "SAP/WAS"

@was = SAP::WAS.new(:url => "https://seahorse.local.net:8443/sap/bc/srt/rfc/sap/Z_RFC_READ_REPORT_01",
                    :lang   => "EN",
                    :client => "010",
                    :user   => "developer",
                    :passwd => "developer",
                    :trace  => true)

# get a list of users
irep = @was.RFC_READ_REPORT
irep.program.value = 'SAPLGRAP'
irep.call()
puts "qtab no rows are: #{irep.qtab.rows.length.to_s}"
puts "qtab rows are: #{irep.qtab.rows.inspect}"

sapwas fully integrates with sap4rails as an alternative driver for accessing either RFCs or SAP SOAP based Web Services, and is available here.

Posted by PiersHarding at 10:48 AM

October 15, 2006

Ruby, Ruby on Rails, and SAP Web Services Integration

Something I like about Scripting Languages is the way they revel in having "more than one way to skin a cat". So, in this spirit I have built a complementary interface to saprfc (for Ruby) called sapwas, that facilitates RFC calls via SAP Web Services. This has been integrated into sap4rails, and the attached example demonstrates how to substitue Web Services for RFC integration in Ruby on Rails.

SAP Web Services vs RFC?

Other than curiosity, there is another motivation for trying this out - Since there has been discussion of late on the merits of RFC and Web Service technology such as SOAP, I thought that inorder to do the subject justice I would do some further (tangible) investigation.

To me, the most obvious way to draw a comparison, is to develop comparable examples of each, with the only difference being the substitution of the technology in question.

This led to me focusing on a recent article I wrote: Ruby on Rails with AJAX, to use as a base line.

Activating the SAP Web Service support

If we take the example above (Ruby on Rails with AJAX), then the changes are as follows:

Install sapwas

Download either the source distribution, or the gem file by following the sapwas project download links. Gem files are easier to deal with - all you need to do is:

gem install sapwas-<version>.gem

And its done (use gem uninstall to remove if its there allready).

You will probably need to install http-access2 inorder to get the basic authentication working correctly. This is a requirement of the SOAP4R library.

Upgrade sap4rails

Download either the source distribution, or the gem file for sap4rails by following the project download links. First remove the old version, and install the new:

gem uninstall sap4rails
gem install sap4rails-<version>.gem

If you have used the source distribution previously, then you will have to manually remove the previous one, and install again (the usual ruby setup.rb dance - gems are soo much easier :-).

Modify the SapUser model

In the Rails application, edit the app/models/sap_user.rb, and change the super class for SapUser:

class SapUser < SAP4Rails::WS::Base
...

Set your Rails configuration

Modify the config/sap.yml file - you really should only need to add in the :url line depicted below, but check anyway:

  client: "010"
  url: "http://seahorse.local.net:8000/sap/bc/soap/rfc"
  user: developer
  passwd: developer
  lang: EN

note on WAS configuration

You must ensure that /sap/bc/soap/rfc is configured/activated correctly in transaction SICF.

Go!

Once you have completed these changes, you can then test the Rails application as described in Ruby on Rails with AJAX - it should function in exactly the same manner - wasn't that easy!

Now you have it working - I'll leave you to draw your own conclussions on it's merits :-)

Posted by PiersHarding at 6:11 PM

October 12, 2006

Changing parameters in saprfc for Ruby

saprfc for Ruby now has the ability to pass Changing type parameters. These are an evolution of import, and export parameter types rolled into one. this functionality is available from release 0.31. This example shows the standard test RFC where COUNTER is a changing type parameter - the value is incremented on each pass:

iter = 10
rfc = SAP::Rfc.new(...)
# look up the interface definition for an RFC
i = rfc.discover("STFC_CHANGING")
i.counter.value = 0
iter.times {|cnt|
  puts "\n\n\n\n\nITERATION #{cnt + 1}\n\n\n\n"
  i.start_value.value = cnt
  rfc.call(i)
  puts "RESULT: #{i.result.value}  COUNTER: #{i.counter.value}"
}
# close the connection
print "close connection: ", rfc.close(), "\n"

Posted by PiersHarding at 6:15 AM

October 11, 2006

SAP::Rfc and saprfc UNICODE support for win32

Over the last few weeks I have been working with Olivier to work through the compiling issues to make UNICODE support for SAP::Rfc for Perl, and saprfc for Ruby available under win32. These both require iconv for the charset conversion, but you need not worry about that as they have been compiled for you as PPD, and GEM respecitvely.

Posted by PiersHarding at 7:14 PM

October 10, 2006

SAP the Enterprise, and Rails interest is building

I've just recently had contact from Lance, at the Engine Yard, who specialise in Rails applicaition development, and Hosting. These guys recognise that for their more Enterprise related clients, there is likely to be an SAP related dimension to their requirements.

To me - this kind of interest shows that Ruby on Rails is making a step change in it's progress through the world of IT, where it will likely start penetrating into the Enterprise software development market.

Posted by PiersHarding at 7:58 AM

October 6, 2006

IM for SAP with Jabber (XMPP)

Jabber and IM is very much in the ascendancy at the moment, thanks to Google Talk which uses the very same XMPP protocol for messaging.

With this in mind I would like to demonstrate how to easily integrate at least some minimal IM capability into SAP, being able to pass basic messages back and forth between IM accounts and R/3 accounts, and then to touch on the potential for IM beyond this.

A bit of background

XMPP

Is an XML streaming protocols for instant messaging and presence developed within the Jabber community. Because the transmission of data is encapsulated in XML, and must conform to the controlling rules of XML, coupled with implementation rules for the protocol such as dialback for server to server communication etc., making XMPP a very secure messaging platform. Testimony to this is the absence of SPAM, in fact it could be robustly argued that if the backbone of SMTP was replaced with XMPP then SPAM would be history (but that is for another day).
Additionally, XMPP is a recognised Standard - the Internet Engineering Task Force (IETF) has formalized the core XML streaming protocols as an approved instant messaging and presence technology under the name of XMPP, and the XMPP specifications have been published as RFC 3920 and RFC 3921.

Jabber

being the historical root of XMPP, has a number of server, client and component implementations surrounding it. In brief, a Jabber environment requires a: For a more indepth ovreview, then this from the JSF is a good starting point.

Jabber and SAP

For my trial implementation, I didn't want to change an R/3 system in anyway, so the logical solution is to start with what SAP has to offer by way of a messaging interface, namely the BCS (Business Communication Service). It is concievably quite easy to modify the BCS to include a new service class along side SMTP, SMS, Faxing etc., but inorder to keep this as "zero modification", I have decided against that route.

The basic solution design is to use email on the R/3 side that is to be bi-directionally translated to Jabber based IM via a custom built XMPP transport component (SMTP Component pictured below).

image

Flow of messages between R/3 and Jabber Server.

Message Flow and Addresses

Because the messages are moving between two protocols, it is necessary to translate the from and to addresses between them, as the messages move through the SMTP transport Component. This is so that a message can find its correct XMPP destination (R/3 -> Jabber), and that the IM Message can be stamped with the appropriate From address so that when a reply is made, it will be able to find it's way back again (Jabber -> R/3).

image

Configure SAPConnect for SMTP

SMTP inbound and outbound must be configured in R/3. There is a good discussion of this in the SAP help here. In the following section I have highlighted the main parts of the configuration that I used to get my SAP Netweaver NW4 evaluation system working - depending on your release your mileage may vary.

Profile Parameters

Set your profile parameters:
   rdisp/start_icman = true
   icm/server_port_2 = PROT=SMTP,PORT=25000,TIMEOUT=180         
   is/SMTP/virt_host_0 = *:25000;                               

SICF Virtual Host configuration

Configure your ICM via transaction SICF:

image
Ensure that your SAPConnect Virtual Host Data is configured for SMTP.

image
On the Service Data tab, ensure that the R/3 user for email receipt is configured (including client, language etc.).

SCOT Configuration

image
In transaction SCOT, select the menu option for default domain - set this as the host receiving the email.

image
In transaction SCOT, you can optionally specify that recipt email is not expected. This makes it tidier in terms of the monitoring view of the send process.

image
Ensure that the SMTP node is configured - it usually uses the local OS transport mechanism such as sendmail (connecting to localhost port 25), and that the address range that will be sent to has a routing table rule in place. Make sure that the job that triggers the send process has been scheduled (SCOT => Settings => Send Jobs) - this is what shuffles the emails out on a periodic basis.

Finally - make sure that every R/3 account is configured correctly with an Internet Email Address. This is found in SU01, under address data, and communication methods.

The Jabber Component

Now that we have R/3 configured, we can move on to the Jabber side of things. I have created a transport component, that implements a simple gateway between XMPP, and SMTP. The component has been developed using Ruby and XMPP4R. By nature, a transport component has two main parts to it. It has the portion that implements the XMPP protocol, and the second part that implements the target protocol - in this case SMTP. There are other SMTP component implementation available such as smtp-t, but - inorder to simplify the sender and receiver addresses (See diagram above and below showing process flow and address translation) - I have decided to "roll my own". XMPP4R is easy to use, and taps into Rubys simple threads implementation - something that is essential for developing components that have two event cycles - listiening for SMTP messages on ones side, and XMPP on the the other.

In my landscape I have a Netweaver R/3 instance with an SMTP interface named seahorse.local.net listening on 2500. My Jabber SMTP component has an SMTP interface of sapsmtp.local.net listening on port 25, and this is registered with the XMPP router called gecko.local.net. As both SAP, and the Component have to have both sending and receiving capabilities for SMTP, and this is all configurable, I've tried to ease this pain with a diagram:

image

Make sure all your designated hostnames are resolvable - this is a common mistake with Jabber.

To run the component you must have installed Ruby and installed the XMPP4R package. This also assumes that you have access to a Jabber server - I use jabberd2, but there are a number available. You can find a good list here. ejabberd is good universal one, especially if you need to run win32.

Once you have access to your server, and have XMPP4R installed, download the component from here. Unpack the .tgz file, and then cd into the smtpcomp/ directory. Here, you need to know the addresses, and port numbers of your landscape to convert them into command line options:

piers@gecko:~/code/ruby/smtpcomp$ ruby smtpcomponent.rb -h
        Usage: smtpcomponent.rb [-h -s -p -a -c -r -q]
        Options
          -h this help
          -s Jabber server router jid (gecko.local.net) - target Jabber server
          -p Jabber server router port (5347) - target Jabber server port for components
          -a Jabber server router auth phrase (secret) 
          -c Jabber component jid and smtpd name (sapsmtp.local.net) - name of THIS component
          -r SAP system smtpd name (seahorse.local.net) - SMTP host of SAP
          -q SAP system smtpd port (2500) - SMTP port of SAP
  
piers@gecko:~/code/ruby/smtpcomp$ 

For my setup where I have a Jabber server, gecko.local.net, a component name of sapsmtp.local.net, and an SAP system seahorse.local.net with an SMTP service on port 2500, then the command line options operate like:

piers@gecko:~/code/ruby/smtpcomp$ sudo ruby smtpcomponent.rb -s gecko.local.net -c sapsmtp.local.net -r seahorse.local.net -q 2500
starting component at: sapsmtp.local.net
SMTPD going to listen on: sapsmtp.local.net/25
gecko.local.net http://jabber.org/protocol/disco#info to sapsmtp.local.net

Note: the use of sudo at the beginning of the command is to make the script run with root priveledges, as the SMTP interface of smtpcomponent.rb listens on port 25 which requires super user access. Also - you may need to specify the port for the component to connect to the router on (-p) and a password for authenticating with the route (-a).

What happens?

To show what happens, the following transcript traces first an R/3 email -> Jabber flow, and then the reverse. In this example, even though the sending R/3 user account is DEVELOPER, I have configured the INET mail address of the R/3 user to be piers@seahorse.local.net, in the user communication section of address details (transaction SU01).

This log section shows the SMTP transcript, the translation of addresses, and then the final construction of an IM message (in XML).

COMM: EHLO seahorse.local.net

COMM: MAIL From:

DID a 250 for MAIL 
COMM: RCPT To:

DID a 250 for RCPT 
COMM: DATA

Message: Is it ready yet!I've been waiting all day blah blah blah ....

DID a 250 for data 
COMM: QUIT

An email was created in R/3 by going to the SAP Office assistant (transaction SO01).

image

The IM Message arrives...

image

Now for the return leg using reply to the original IM Message, which is translated back through the SMTP component and sent to R/3.

Message from piers@gecko.local.net/Psi to piers@sapsmtp.local.net () subject: Re: Is it ready yet! : "no - stop pestering me"

image

Email in R/3

image

So what does this all mean?

What we have here is the ability to push events between R/3, and "A" another endpoint. By virtue of transport components, these events can traverse protocols, and can be integrated with just about any platform you care to think of because of client programming language support for XMPP (C, Java, Perl, Python, Ruby, Erlang to name some). To me, this all spells a universal messaging platform that is open, reliable, secure, standards compliant, that is ready to be used as a carrier for business data from alerts, to documents, to workflow events. It is worth taking a look at the Jabber Protocols page, which describes what processes, and functionality is currently supported, and what things are in the pipeline.

Currently Jabber clients routinely handle URLs, which make a good starting point for relaying Workflow items (integration points for BSPs, EP etc.). It also has specifications for RPC style encapsulation, and reference implementations for SOAP document transmission. Beyond this, Jabber messaging has the potential for embedding workflow objects ala Duet, to be interpreted by an extension to an existing Jabber client, and I haven't even started on mobile technologies yet.

Please note that I have quoted extensively from documentation supplied by the JSF throughout, and wish to thank them for that and their continuing efforts in developing, and promoting Jabber and XMPP.

Posted by PiersHarding at 11:10 AM