sapnwrfc 0.23-i686-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
data/lib/sapnwrfc.rb ADDED
@@ -0,0 +1,217 @@
1
+ #
2
+ #
3
+ # = SAPNWRFC - SAP Netweaver RFC support for Ruby
4
+ #
5
+ # Welcome to sapnwrfc !
6
+ #
7
+ # sapnwrfc is an RFC based connector to SAP specifically designed for use with the
8
+ # next generation RFC SDK supplied by SAP for NW2004+ .
9
+ #
10
+ # = Download and Documentation
11
+ #
12
+ # Documentation at: http://www.piersharding.com/download/ruby/sapnwrfc/doc/
13
+ #
14
+ # Project and Download at: http://raa.ruby-lang.org/project/sapnwrfc
15
+ #
16
+ # = Functionality
17
+ #
18
+ # The next generation RFCSDK from SAP provides a number of interesting new features. The two most
19
+ # important are:
20
+ # * UNICODE support
21
+ # * deep/nested structures
22
+ #
23
+ # The UNICODE support is built fundamentally into the core of the new SDK, and as a result this is reflected in
24
+ # sapnwrfc. sapnwrfc takes UTF-8 as its only input character set, and handles the translation of this to UTF-16
25
+ # as required by the RFCSDK.
26
+ #
27
+ # Deep and complex structures are now supported fully. Please see the test_deep.rb example in tests/ for
28
+ # an idea as to how it works.
29
+ #
30
+ # sapnwrfc is a departure to the way the original saprfc (http://raa.ruby-lang.org/project/saprfc) works.
31
+ # It aims to simplify the exchange of native Ruby data types between the user application and the
32
+ # connector. This means that the following general rules should be observered, when passing values
33
+ # to and from RFC interface parameters and tables:
34
+ #
35
+ # * Tables expect Arrays of Hashes.
36
+ # * Parameters with structures expect Hashes
37
+ # * CHAR, DATE, TIME, STRING, XSTRING, and BYTE type parameters expect String values.
38
+ # * all numeric parameter values must be Fixnum, Bignum or Float.
39
+ #
40
+ #
41
+ # = Building and Installation
42
+ #
43
+ # After you have unpacked your kit, you should have all the files listed in the MANIFEST.
44
+ #
45
+ # In brief, the following should work on most systems: ruby setup.rb
46
+ #
47
+ # if your rfcsdk is not findable in the system search path, then use the command line switches
48
+ # for mkmf/setup.rb like so:
49
+ # ruby setup.rb config --with-nwrfcsdk-dir=/path/to/rfcsdk
50
+ # ruby setup.rb setup
51
+ # ruby setup.rb install
52
+ #
53
+ # You must otain the latest RFCSDK for Netweaver from SAP - this <b>MUST</b> be the next
54
+ # generation SDK, if you are to have any chance of succeeding.
55
+ #
56
+ #
57
+ # = WIN32 Support
58
+ #
59
+ # When Olivier (or anyone else offering) supplies prebuilt GEM files, I make them available
60
+ # on http://www.piersharding.com/download/ruby/sapnwrfc/ .
61
+ #
62
+ #
63
+ # = Support
64
+ #
65
+ # For both community based, and professional support, I can be contacted at Piers Harding <piers@ompka.net>.
66
+ #
67
+ # = Examples
68
+ #
69
+ # Please see the examples (test/*.rb) distributed with this packages (download source for this) for
70
+ # a comprehensive shake-down on what you can do.
71
+ #
72
+ # Here is a taster using the standard Flight demo BAPIs supplied by SAP:
73
+ #
74
+ # require 'sapnwrfc'
75
+ #
76
+ # TEST_FILE = 'ubuntu.yml'
77
+ #
78
+ # # specify the YAML config source and load
79
+ # SAPNW::Base.config_location = TEST_FILE
80
+ # SAPNW::Base.load_config
81
+ #
82
+ # # Connec to SAP
83
+ # conn = SAPNW::Base.rfc_connect
84
+ #
85
+ # # Inspect the connection attributes
86
+ # attrib = conn.connection_attributes
87
+ # $stderr.print "Connection Attributes: #{attrib.inspect}\n"
88
+ #
89
+ # # pull in your RFC definitions
90
+ # fld = conn.discover("BAPI_FLIGHT_GETLIST")
91
+ # flgd = conn.discover("BAPI_FLIGHT_GETDETAIL")
92
+ # fd = conn.discover("BAPI_FLBOOKING_CREATEFROMDATA")
93
+ #
94
+ # # get a new handle for each function call to be invoked
95
+ # fl = fld.new_function_call
96
+ #
97
+ # # set the parameters for the call
98
+ # fl.AIRLINE = "AA "
99
+ #
100
+ # # ivoke the call
101
+ # fl.invoke
102
+ #
103
+ # # interogate the results
104
+ # fl.FLIGHT_LIST.each do |row|
105
+ # $stderr.print "row: #{row.inspect}\n"
106
+ #
107
+ # # for each flight now do another RFC call to get the details
108
+ # flg = flgd.new_function_call
109
+ # flg.AIRLINEID = row['AIRLINEID']
110
+ # flg.CONNECTIONID = row['CONNECTID']
111
+ # flg.FLIGHTDATE = row['FLIGHTDATE']
112
+ # flg.invoke
113
+ # $stderr.print "\tflight data: #{flg.FLIGHT_DATA.inspect}\n"
114
+ # $stderr.print "\tadditional info: #{flg.ADDITIONAL_INFO.inspect}\n"
115
+ # $stderr.print "\tavailability: #{flg.AVAILIBILITY.inspect}\n"
116
+ # end
117
+ #
118
+ # # create a new booking
119
+ # fd.name == "BAPI_FLBOOKING_CREATEFROMDATA"
120
+ # f = fd.new_function_call
121
+ # f.BOOKING_DATA = { 'AIRLINEID' => "AA ", 'CONNECTID' => "0001", 'FLIGHTDATE' => "20070130",
122
+ # 'CLASS' => "F", 'CUSTOMERID' => "00000001", 'AGENCYNUM' => '00000093' }
123
+ #
124
+ # # trap Function Call exceptions
125
+ # begin
126
+ # f.invoke
127
+ # rescue SAPNW::RFC::FunctionCallException => e
128
+ # $stderr.print "FunctionCallException: #{e.error.inspect}\n"
129
+ # raise "gone"
130
+ # end
131
+ # f.RETURN.each do |row|
132
+ # $stderr.print "row: #{row.inspect}\n"
133
+ # end
134
+ #
135
+ # # use the standard COMMIT BAPI to commit the update
136
+ # cd = conn.discover("BAPI_TRANSACTION_COMMIT")
137
+ # c = cd.new_function_call
138
+ # c.WAIT = "X"
139
+ # c.invoke
140
+ #
141
+ # # close the RFC connection and destroy associated resources
142
+ # conn.close
143
+ #
144
+ #
145
+ #
146
+ # = A Closer Look At Handling Parameters
147
+ #
148
+ # Complex parameter types map naturally to Ruby data types.
149
+ # Parameters that require structures are represented by a Hash of field/value pairs eg:
150
+ # f.BOOKING_DATA = { 'AIRLINEID' => "AA ", 'CONNECTID' => "0001", 'FLIGHTDATE' => "20070130",
151
+ # 'CLASS' => "F", 'CUSTOMERID' => "00000001", 'AGENCYNUM' => '00000093' }
152
+ # Parameters that require tables are represented by an Array of Hashes of field/value pairs eg:
153
+ # ft.IMPORT_TAB = [{ 'I' => 123, 'C' => 'AbCdEf',
154
+ # 'STR' => 'The quick brown fox ...',
155
+ # 'XSTR' => ["deadbeef"].pack("H*") }]
156
+ #
157
+ #
158
+ # = Building your RFC Call
159
+ #
160
+ # When building a call for client-side RFC, you should always be inspecting the requirements
161
+ # of the RFC call by using transaction SE37 first. You should also be in the the habit of
162
+ # testing out your RFC calls first using SE37 too. YOu would be amazed how much this simple
163
+ # approach will save you (and me) time.
164
+ #
165
+ #
166
+ #
167
+ # = Thanks to:
168
+ #
169
+ # * Olivier Boudry - an Open Source guy
170
+ # * Craig Cmehil - SAP, and SDN
171
+ # * Ulrich Schmidt - SAP
172
+ # For their help in making this possible.
173
+ #
174
+ #
175
+ #
176
+ #
177
+ # Author:: Piers Harding <piers@ompka.net>
178
+ # License:: Copyright (c) 2006-2008 Piers Harding. sapnwrfc is free software, and may be redistributed under the terms specified in the README file of the Ruby distribution.
179
+ # Requires:: Ruby 1.9.0 or later
180
+ #
181
+
182
+
183
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
184
+
185
+ require 'yaml'
186
+ require 'fileutils'
187
+ require 'logger'
188
+
189
+ # setup defaults for logging
190
+ SAP_LOGGER = Logger.new(STDERR)
191
+ SAP_LOGGER.datetime_format = "%Y-%m-%d %H:%M:%S"
192
+ SAP_LOGGER.level = Logger::WARN
193
+
194
+ require 'sapnwrfc/base'
195
+
196
+ # C extension
197
+ begin
198
+ require 'nwsaprfc'
199
+ rescue LoadError => e
200
+ SAP_LOGGER.error("Could not load nwsaprfc. Make sure nwrfcsdk libraries are properly installed: #{e.message}")
201
+ raise e
202
+ end
203
+
204
+ require 'sapnwrfc/config'
205
+ require 'sapnwrfc/connection'
206
+ require 'sapnwrfc/server'
207
+ require 'sapnwrfc/functions'
208
+ require 'sapnwrfc/parameters'
209
+
210
+ SAPNW::Base.class_eval do
211
+ include SAPNW::Config
212
+ include SAPNW::Connections
213
+ include SAPNW::Servers
214
+ include SAPNW::Functions
215
+ include SAPNW::Parameters
216
+ end
217
+
@@ -0,0 +1,41 @@
1
+ # SAPNW is Copyright (c) 2006-2008 Piers Harding. It is free software, and
2
+ # may be redistributed under the terms specified in the README file of
3
+ # the Ruby distribution.
4
+ #
5
+ # Welcome to sapnwrfc !
6
+ #
7
+ # sapnwrfc is a RFC based connector to SAP specifically designed for use with the
8
+ # next generation RFC SDK supplied by SAP for NW2004+ .
9
+ #
10
+ #
11
+ #
12
+
13
+ module SAPNW
14
+
15
+ # Some doco in the SAPNW module
16
+ class Base
17
+
18
+ # some doco in Base
19
+
20
+ @@rfc_connections = {}
21
+
22
+
23
+ # def rfc_connection(*args)
24
+ # return SAPNW::RFC::Connection.connect(args)
25
+ # end
26
+ #
27
+ # def rfc_register(*args)
28
+ # return SAPNW::RFC::Server.connect(args)
29
+ # end
30
+ #
31
+ # def installFunction(*args)
32
+ # return SAPNW::RFC::Server.installFunction(args)
33
+ # end
34
+ #
35
+ def Base.finalize(id)
36
+ SAP_LOGGER.debug("[#{self.class}] finalize called")
37
+ end
38
+
39
+ end
40
+ end
41
+
@@ -0,0 +1,113 @@
1
+ # SAPNW is Copyright (c) 2006-2008 Piers Harding. It is free software, and
2
+ # may be redistributed under the terms specified in the README file of
3
+ # the Ruby distribution.
4
+ #
5
+ # Configuration for an RFC connection can be passed in two distinct ways, but those two methods
6
+ # can be combined together.
7
+ #
8
+ # (1) Config is loaded via a YAML based config file
9
+ # (2) Config is passed in the code directly into the connection
10
+ # (3) a combination of (1) and (2), where (2) overides (1) at run time.
11
+ #
12
+ # YAML config file format:
13
+ #
14
+ # ashost: ubuntu.local.net
15
+ # sysnr: "01"
16
+ # client: "001"
17
+ # user: developer
18
+ # passwd: developer
19
+ # lang: EN
20
+ # trace: 2
21
+ #
22
+ # At connection time, any valid parameters can be added or over ridden:
23
+ #
24
+ # conn = SAPNW::Base.rfc_connect(:user => 'developer', :passwd => 'developer')
25
+ #
26
+ # Valid connection parameters are:
27
+ # ashost
28
+ # dest - used in conjunction with sapnwrfc.ini file
29
+ # mshost
30
+ # group
31
+ # sysid
32
+ # msserv
33
+ # sysnr
34
+ # lang
35
+ # client
36
+ # user
37
+ # passwd
38
+ # trace
39
+ # tpname
40
+ # gwhost
41
+ # gwserv
42
+ # codepage
43
+ # x509cert
44
+ # extiddata
45
+ # extidtype
46
+ # mysapsso2
47
+ # mysapsso
48
+ # getsso2
49
+ # snc_mode
50
+ # snc_qop
51
+ # snc_myname
52
+ # snc_partnername
53
+ # snc_lib
54
+ #
55
+ #
56
+ #
57
+ # Author:: Piers Harding <piers@ompka.net>
58
+ # Requires:: Ruby 1.9 or later
59
+ #
60
+
61
+ Logger.class_eval do
62
+ def set_logdev(logfile, logfile_age = 0, logfile_size = 1048576)
63
+ @logdev = Logger::LogDevice.new(logfile, :shift_age => logfile_age, :shift_size => logfile_size)
64
+ end
65
+ end
66
+
67
+ module SAPNW
68
+ module Config
69
+ class << SAPNW::Base
70
+
71
+ @configuration = {}
72
+
73
+ attr_accessor :config_location, :config
74
+
75
+ def load_config
76
+ file = self.config_location || './sap.yml'
77
+ SAP_LOGGER.fatal("[#{self.name}] Configuration file not found: #{file}") unless FileTest.exists?(file)
78
+ self.config = File.open(file) { |f| YAML::load(f) }
79
+ SAP_LOGGER.debug("[#{self.name}] Configuration: " + self.config.inspect)
80
+
81
+ if self.config.key? 'logfile'
82
+ if /STDOUT/i.match(self.config['logfile'])
83
+ SAP_LOGGER.set_logdev(STDOUT)
84
+ else
85
+ SAP_LOGGER.set_logdev(self.config['logfile'],
86
+ self.config['logfile_age'] || 0,
87
+ self.config['logfile_size'] || 1048576)
88
+ SAP_LOGGER.datetime_format = "%Y-%m-%d %H:%M:%S"
89
+ end
90
+ end
91
+ if self.config.key? 'loglevel'
92
+ case self.config['loglevel'].upcase
93
+ when 'FATAL'
94
+ SAP_LOGGER.level = Logger::FATAL
95
+ when 'ERROR'
96
+ SAP_LOGGER.level = Logger::ERROR
97
+ when 'WARN'
98
+ SAP_LOGGER.level = Logger::WARN
99
+ when 'INFO'
100
+ SAP_LOGGER.level = Logger::INFO
101
+ when 'DEBUG'
102
+ SAP_LOGGER.level = Logger::DEBUG
103
+ end
104
+ else
105
+ # set default
106
+ SAP_LOGGER.level = Logger::WARN
107
+ end
108
+ return self.config
109
+ end
110
+
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,153 @@
1
+ # SAPNW is Copyright (c) 2006-2008 Piers Harding. It is free software, and
2
+ # may be redistributed under the terms specified in the README file of
3
+ # the Ruby distribution.
4
+ #
5
+ # Author:: Piers Harding <piers@ompka.net>
6
+ # Requires:: Ruby 1.9 or later
7
+ #
8
+
9
+ module SAPNW
10
+ module Connections
11
+
12
+ class << SAPNW::Base
13
+
14
+ # Build a connection to an R/3 system (ABAP AS)
15
+ #
16
+ # Connection parameters can be passed in a variety of ways
17
+ # (a) via a YAML based configuration file
18
+ # (b) a Hash of parameter arguments
19
+ # (c) a combination of both
20
+ def rfc_connect(args = nil)
21
+ parms = {}
22
+ self.config = {} unless self.config
23
+ parms[:ashost] = self.config['ashost'] if self.config.key? 'ashost'
24
+ parms[:dest] = self.config['dest'] if self.config.key? 'dest'
25
+ parms[:mshost] = self.config['mshost'] if self.config.key? 'mshost'
26
+ parms[:group] = self.config['group'] if self.config.key? 'group'
27
+ parms[:sysid] = self.config['sysid'] if self.config.key? 'sysid'
28
+ parms[:msserv] = self.config['msserv'] if self.config.key? 'msserv'
29
+ parms[:sysnr] = self.config['sysnr'] if self.config.key? 'sysnr'
30
+ parms[:lang] = self.config['lang'] if self.config.key? 'lang'
31
+ parms[:client] = self.config['client'] if self.config.key? 'client'
32
+ parms[:user] = self.config['user'] if self.config.key? 'user'
33
+ parms[:passwd] = self.config['passwd'] if self.config.key? 'passwd'
34
+ parms[:trace] = self.config['trace'].to_i if self.config.key? 'trace'
35
+ parms[:codepage] = self.config['codepage'].to_i if self.config.key? 'codepage'
36
+ parms[:x509cert] = self.config['x509cert'] if self.config.key? 'x509cert'
37
+ parms[:extiddata] = self.config['extiddata'] if self.config.key? 'extiddata'
38
+ parms[:extidtype] = self.config['extidtype'] if self.config.key? 'extidtype'
39
+ parms[:mysapsso2] = self.config['mysapsso2'] if self.config.key? 'mysapsso2'
40
+ parms[:mysapsso] = self.config['mysapsso'] if self.config.key? 'mysapsso'
41
+ parms[:getsso2] = self.config['getsso2'].to_i if self.config.key? 'getsso2'
42
+ parms[:snc_mode] = self.config['snc_mode'] if self.config.key? 'snc_mode'
43
+ parms[:snc_qop] = self.config['snc_qop'] if self.config.key? 'snc_qop'
44
+ parms[:snc_myname] = self.config['snc_myname'] if self.config.key? 'snc_myname'
45
+ parms[:snc_partnername] = self.config['snc_partnername'] if self.config.key? 'snc_partnername'
46
+ parms[:snc_lib] = self.config['snc_lib'] if self.config.key? 'snc_lib'
47
+ SAP_LOGGER.debug("[" + self.name + "] base parameters to be passed are: " + parms.inspect)
48
+
49
+ case args
50
+ when nil
51
+ when Hash
52
+ parms[:ashost] = args[:ashost] if args.key? :ashost
53
+ parms[:dest] = args[:dest] if args.key? :dest
54
+ parms[:mshost] = args[:mshost] if args.key? :mshost
55
+ parms[:sysid] = args[:sysid] if args.key? :sysid
56
+ parms[:group] = args[:group] if args.key? :group
57
+ parms[:msserv] = args[:msserv] if args.key? :msserv
58
+ parms[:sysnr] = args[:sysnr] if args.key? :sysnr
59
+ parms[:lang] = args[:lang] if args.key? :lang
60
+ parms[:client] = args[:client] if args.key? :client
61
+ parms[:user] = args[:user] if args.key? :user
62
+ parms[:passwd] = args[:passwd] if args.key? :passwd
63
+ parms[:trace] = args[:trace].to_i if args.key? :trace
64
+ parms[:codepage] = args[:codepage].to_i if args.key? :codepage
65
+ parms[:x509cert] = args[:x509cert] if args.key? :x509cert
66
+ parms[:extiddata] = args[:extiddata] if args.key? :extiddata
67
+ parms[:extidtype] = args[:extidtype] if args.key? :extidtype
68
+ parms[:mysapsso2] = args[:mysapsso2] if args.key? :mysapsso2
69
+ parms[:mysapsso] = args[:mysapsso] if args.key? :mysapsso
70
+ parms[:getsso2] = args[:getsso2].to_i if args.key? :getsso2
71
+ parms[:snc_mode] = args[:snc_mode] if args.key? :snc_mode
72
+ parms[:snc_qop] = args[:snc_qop] if args.key? :snc_qop
73
+ parms[:snc_myname] = args[:snc_myname] if args.key? :snc_myname
74
+ parms[:snc_partnername] = args[:snc_partnername] if args.key? :snc_partnername
75
+ parms[:snc_lib] = args[:snc_lib] if args.key? :snc_lib
76
+ SAP_LOGGER.debug("[" + self.name + "] with EXTRA parameters to be passed are: " + parms.inspect)
77
+ else
78
+ raise "Wrong parameters for Connection - must pass a Hash\n"
79
+ end
80
+
81
+
82
+ connection = SAPNW::RFC::Connection.new(parms)
83
+ SAP_LOGGER.debug("completed the connection (#{connection.handle.class}/#{connection.handle.object_id}) ...")
84
+ return connection
85
+
86
+ end
87
+ end
88
+ end
89
+
90
+ module RFC
91
+ class Connection
92
+ attr_accessor :handle
93
+ attr_reader :connection_parameters, :functions
94
+
95
+ def initialize(args = nil)
96
+ @connection_parameters = []
97
+ case args
98
+ when nil
99
+ when Hash
100
+ args.each_pair { |key, val|
101
+ @connection_parameters << {'name' => key.to_s, 'value' => val.to_s}
102
+ }
103
+ else
104
+ raise "Wrong parameters for Connection - must pass a Hash\n"
105
+ end
106
+ SAP_LOGGER.debug("In #{self.class} initialize: #{@connection_parameters.inspect} ...")
107
+ @functions = {}
108
+ @handle = SAPNW::RFC::Handle.new(self)
109
+ end
110
+
111
+ def connection_attributes
112
+ SAP_LOGGER.debug("In #{self.class} connection_attributes ...")
113
+ return self.handle.connection_attributes()
114
+ end
115
+
116
+ # discover() looks up the dictionary definition of an RFC interface
117
+ # storing away the meta data of the associated Parameters/Tables and returns this
118
+ # as an instance of SAPNW::RFC::FunctionDescriptor. This is the MANDATORY starting
119
+ # point of all client side RFC.
120
+ def discover(func = nil)
121
+ SAP_LOGGER.debug("In #{self.class} discover (#{func}) ...")
122
+ case func
123
+ when nil
124
+ return nil
125
+ else
126
+ func_def = self.handle.function_lookup(SAPNW::RFC::FunctionDescriptor, SAPNW::RFC::Parameter, func.to_s)
127
+ @functions[func_def.name] = func_def
128
+ return func_def
129
+ end
130
+ end
131
+
132
+ # terminate an established RFC connection. This will invalidate any currently in-scope
133
+ # FunctionDescriptors associated with this Connection.
134
+ def close
135
+ SAP_LOGGER.debug("In #{self.class} close ...")
136
+ return nil unless self.handle
137
+ SAP_LOGGER.debug("In #{self.class} handle: #{self.handle} ...")
138
+ res = self.handle.close()
139
+ self.handle = nil
140
+ # XXX Should destroy all cached functions and structures and types tied to handle ?
141
+ return true
142
+ end
143
+
144
+ # ping test a connection to see if it is still alive
145
+ def ping
146
+ SAP_LOGGER.debug("In #{self.class} ping ...")
147
+ return nil unless self.handle
148
+ SAP_LOGGER.debug("In #{self.class} handle: #{self.handle} ...")
149
+ return self.handle.ping()
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,179 @@
1
+ # SAPNW is Copyright (c) 2006-2008 Piers Harding. It is free software, and
2
+ # may be redistributed under the terms specified in the README file of
3
+ # the Ruby distribution.
4
+ #
5
+ # Author:: Piers Harding <piers@ompka.net>
6
+ # Requires:: Ruby 1.9 or later
7
+ #
8
+
9
+ module SAPNW
10
+ module Functions
11
+ class Base
12
+
13
+ end
14
+ end
15
+
16
+ module RFC
17
+
18
+ # These are automatically created as a result of SAPNW::RFC::Connection#discover() -
19
+ # do not instantiate these yourself yourself!
20
+ #
21
+ class FunctionDescriptor
22
+ attr_reader :name, :parameters
23
+ attr_accessor :callback
24
+
25
+ # create a new SAPNW::RFC::FunctionCall object for this FunctionDescriptor.
26
+ #
27
+ # You must call this each time that you want to invoke() a new function call, as
28
+ # this creates a one shot container for the passing back and forth of interface parameters.
29
+ def new_function_call
30
+ return create_function_call(SAPNW::RFC::FunctionCall)
31
+ end
32
+
33
+ def make_empty_function_call
34
+ return SAPNW::RFC::FunctionCall.new(self)
35
+ end
36
+
37
+ def callback=(proc)
38
+ if proc.instance_of?(Proc)
39
+ @callback = proc
40
+ else
41
+ raise "Must pass in an instance of Proc for the callback"
42
+ end
43
+ return @callback
44
+ end
45
+
46
+ def handler(function)
47
+ begin
48
+ return @callback.call(function)
49
+ rescue SAPNW::RFC::ServerException => e
50
+ #$stderr.print "ServerException => #{e.error.inspect}\n"
51
+ return e
52
+ rescue StandardError => e
53
+ #$stderr.print "StandardError => #{e.inspect}/#{e.message}\n"
54
+ return SAPNW::RFC::ServerException.new({'code' => 3, 'key' => 'RUBY_RUNTIME', 'message' => e.message})
55
+ end
56
+ end
57
+
58
+ def method_missing(methid, *rest)
59
+ meth = methid.id2name
60
+ if @parameters.has_key?(meth)
61
+ return @parameters[meth]
62
+ else
63
+ raise NoMethodError
64
+ end
65
+ end
66
+
67
+ # internal method used to add parameters from within the C extension
68
+ #def addParameter(name = nil, direction = 0, type = 0, len = 0, ulen = 0, decimals = 0)
69
+ def addParameter(*parms)
70
+ parms = parms.first if parms.class == Array and (parms.first.class == Hash || parms.first.kind_of?(SAPNW::RFC::Parameter))
71
+ case parms
72
+ when Array
73
+ name, direction, type, len, ulen, decimals = parms
74
+ when Hash
75
+ name = parms.has_key?(:name) ? parms[:name] : nil
76
+ direction = parms.has_key?(:direction) ? parms[:direction] : nil
77
+ type = parms.has_key?(:type) ? parms[:type] : nil
78
+ len = parms.has_key?(:len) ? parms[:len] : nil
79
+ ulen = parms.has_key?(:ulen) ? parms[:ulen] : nil
80
+ decimals = parms.has_key?(:decimals) ? parms[:decimals] : nil
81
+ when SAPNW::RFC::Export, SAPNW::RFC::Import, SAPNW::RFC::Changing, SAPNW::RFC::Table
82
+ # this way happens when a function def is manually defined
83
+ self.add_parameter(parms)
84
+ @parameters[parms.name] = parms
85
+ return parms
86
+ else
87
+ raise "invalid SAPNW::RFC::FunctionDescriptor parameter supplied: #{parms.inspect}\n"
88
+ end
89
+
90
+ #$stderr.print "parm: #{name} direction: #{direction} type: #{type} len: #{len} decimals: #{decimals}\n"
91
+ case direction
92
+ when SAPNW::RFC::IMPORT
93
+ if @parameters.has_key?(name) and @parameters[name].direction == SAPNW::RFC::EXPORT
94
+ p = SAPNW::RFC::Changing.new(self, name, type, len, ulen, decimals)
95
+ else
96
+ p = SAPNW::RFC::Import.new(self, name, type, len, ulen, decimals)
97
+ end
98
+ when SAPNW::RFC::EXPORT
99
+ if @parameters.has_key?(name) and @parameters[name].direction == SAPNW::RFC::IMPORT
100
+ p = SAPNW::RFC::Changing.new(self, name, type, len, ulen, decimals)
101
+ else
102
+ p = SAPNW::RFC::Export.new(self, name, type, len, ulen, decimals)
103
+ end
104
+ when SAPNW::RFC::CHANGING
105
+ p = SAPNW::RFC::Changing.new(self, name, type, len, ulen, decimals)
106
+ when SAPNW::RFC::TABLES
107
+ p = SAPNW::RFC::Table.new(self, name, type, len, ulen, decimals)
108
+ else
109
+ raise "unknown direction (#{name}): #{direction}\n"
110
+ end
111
+ @parameters[p.name] = p
112
+ return p
113
+ end
114
+
115
+ end
116
+
117
+ class FunctionCall
118
+ attr_reader :function_descriptor, :name, :parameters
119
+
120
+ # These are automatically created as a result of SAPNW::RFC::FunctionDescriptor#new_function_call() -
121
+ # do not instantiate these yourself!
122
+ #
123
+ # SAPNW::RFC::FunctionCall objects allow dynamic method calls of parameter, and table names
124
+ # for the setting and getting of interface values eg:
125
+ # fd = conn.discover("RFC_READ_TABLE")
126
+ # f = fd.new_function_call
127
+ # f.QUERY_TABLE = "T000" # <- QUERY_TABLE is a dynamic method serviced by method_missing
128
+ #def initialize(fd=nil)
129
+ def initialize(fd=nil)
130
+ @parameters = {}
131
+ if fd == nil
132
+ @function_descriptor.parameters.each_pair do |k, v|
133
+ @parameters[k] = v.clone
134
+ end
135
+ else
136
+ fd.parameters.each_pair do |k, v|
137
+ @parameters[k] = v.clone
138
+ end
139
+ end
140
+ @parameters_list = @parameters.values || []
141
+ end
142
+
143
+ # activate a parameter - parameters are active by default so it is unlikely that this
144
+ # would ever need to be called.
145
+ def activate(parm=nil)
146
+ raise "Parameter not found: #{parm}\n" unless @parameters.has_key?(parm)
147
+ return set_active(parm, 1)
148
+ end
149
+
150
+ # deactivate a parameter - parameters can be deactivated for a function call, to reduce the
151
+ # amount of RFC traffic on the wire. This is especially important for unrequired tables, or
152
+ # parameters that are similar sources of large data transfer.
153
+ def deactivate(parm=nil)
154
+ raise "Parameter not found: #{parm}\n" unless @parameters.has_key?(parm)
155
+ return set_active(parm, 0)
156
+ end
157
+
158
+ # dynamic method calls for parameters and tables
159
+ def method_missing(methid, *rest)
160
+ meth = methid.id2name
161
+ #$stderr.print "method_missing: #{meth}\n"
162
+ #$stderr.print "parameters: #{@parameters.keys.inspect}\n"
163
+ if @parameters.has_key?(meth)
164
+ #$stderr.print "return parm obj\n"
165
+ return @parameters[meth].value
166
+ elsif mat = /^(.*?)\=$/.match(meth)
167
+ #$stderr.print "return parm val\n"
168
+ if @parameters.has_key?(mat[1])
169
+ return @parameters[mat[1]].value = rest[0]
170
+ else
171
+ raise NoMethError
172
+ end
173
+ else
174
+ raise NoMethodError
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,332 @@
1
+ # SAPNW is Copyright (c) 2006-2008 Piers Harding. It is free software, and
2
+ # may be redistributed under the terms specified in the README file of
3
+ # the Ruby distribution.
4
+ #
5
+ # Author:: Piers Harding <piers@ompka.net>
6
+ # Requires:: Ruby 1.9 or later
7
+ #
8
+
9
+ module SAPNW
10
+ module Parameters
11
+
12
+ # base class for all parameters
13
+ class Base
14
+
15
+ # they all have:
16
+ # a name
17
+ # may or may not have a structure = a type
18
+ # type may be complex or simple
19
+ #
20
+ #
21
+
22
+ end
23
+ end
24
+
25
+ module RFC
26
+
27
+ # Parameter types
28
+ IMPORT = 1
29
+ EXPORT = 2
30
+ CHANGING = 3
31
+ TABLES = 7
32
+
33
+ # basic data types
34
+ CHAR = 0
35
+ DATE = 1
36
+ BCD = 2
37
+ TIME = 3
38
+ BYTE = 4
39
+ TABLE = 5
40
+ NUM = 6
41
+ FLOAT = 7
42
+ INT = 8
43
+ INT2 = 9
44
+ INT1 = 10
45
+ NULL = 14
46
+ STRUCTURE = 17
47
+ DECF16 = 23
48
+ DECF34 = 24
49
+ XMLDATA = 28
50
+ STRING = 29
51
+ XSTRING = 30
52
+ EXCEPTION = 98
53
+
54
+ # return codes
55
+ RFC_OK = 0
56
+ RFC_COMMUNICATION_FAILURE = 1
57
+ RFC_LOGON_FAILURE = 2
58
+ RFC_ABAP_RUNTIME_FAILURE = 3
59
+ RFC_ABAP_MESSAGE = 4
60
+ RFC_ABAP_EXCEPTION = 5
61
+ RFC_CLOSED = 6
62
+ RFC_CANCELED = 7
63
+ RFC_TIMEOUT = 8
64
+ RFC_MEMORY_INSUFFICIENT = 9
65
+ RFC_VERSION_MISMATCH = 10
66
+ RFC_INVALID_PROTOCOL = 11
67
+ RFC_SERIALIZATION_FAILURE = 12
68
+ RFC_INVALID_HANDLE = 13
69
+ RFC_RETRY = 14
70
+ RFC_EXTERNAL_FAILURE = 15
71
+ RFC_EXECUTED = 16
72
+ RFC_NOT_FOUND = 17
73
+ RFC_NOT_SUPPORTED = 18
74
+ RFC_ILLEGAL_STATE = 19
75
+ RFC_INVALID_PARAMETER = 20
76
+ RFC_CODEPAGE_CONVERSION_FAILURE = 21
77
+ RFC_CONVERSION_FAILURE = 22
78
+ RFC_BUFFER_TOO_SMALL = 23
79
+ RFC_TABLE_MOVE_BOF = 24
80
+ RFC_TABLE_MOVE_EOF = 25
81
+
82
+
83
+ # Base class for all Parameter types
84
+ class Parameter < SAPNW::Parameters::Base
85
+ attr_reader :name, :type, :typdef, :direction, :len, :ulen, :decimals, :value
86
+
87
+ # constructor called only from the SAPNW::RFC::Connector#discover process
88
+ #def initialize(funcdesc, name, type, len, ulen, decimals)
89
+ def initialize(*parms)
90
+ parms = parms.first if parms.class == Array and parms.first.class == Hash
91
+ case parms
92
+ when Array
93
+ # this way happens when the interface of the parameter has been discover()ed
94
+ funcdesc, name, type, len, ulen, decimals, typedef = parms
95
+ when Hash
96
+ # This way happens when a parameter is being manually constructed
97
+ raise "Missing parameter :name => #{parms.inspect}\n" unless parms.has_key?(:name)
98
+ raise "Missing parameter :type => #{parms.inspect}\n" unless parms.has_key?(:type)
99
+ case parms[:type]
100
+ when SAPNW::RFC::CHAR, SAPNW::RFC::DATE, SAPNW::RFC::BCD, SAPNW::RFC::TIME, SAPNW::RFC::BYTE, SAPNW::RFC::TABLE, SAPNW::RFC::NUM, SAPNW::RFC::FLOAT, SAPNW::RFC::INT, SAPNW::RFC::INT2, SAPNW::RFC::INT1, SAPNW::RFC::NULL, SAPNW::RFC::STRUCTURE, SAPNW::RFC::DECF16, SAPNW::RFC::DECF34, SAPNW::RFC::XMLDATA, SAPNW::RFC::STRING, SAPNW::RFC::XSTRING, SAPNW::RFC::EXCEPTION
101
+ else
102
+ if parms[:type].class == SAPNW::RFC::Type
103
+ parms[:typedef] = parms[:type]
104
+ parms[:type] = parms[:typedef].type
105
+ raise "Parameter type (#{self.class}) does not match Type type (#{parms[:typedef].inspect})\n" if self.class == SAPNW::RFC::Table and parms[:type] != SAPNW::RFC::TABLE
106
+ else
107
+ raise "Invalid SAPNW::RFC* type supplied (#{parms[:type]})\n"
108
+ end
109
+ end
110
+ funcdesc = nil
111
+ len = 0
112
+ ulen = 0
113
+ decimals = 0
114
+ name = parms[:name]
115
+ type = parms[:type]
116
+ typedef = parms[:typedef] if parms.has_key?(:typedef)
117
+ len = parms[:len] if parms.has_key?(:len)
118
+ ulen = parms[:ulen] if parms.has_key?(:ulen)
119
+ decimals = parms[:decimals] if parms.has_key?(:decimals)
120
+ else
121
+ raise "invalid parameters: #{parms.inspect}\n"
122
+ end
123
+ @function_descriptor = funcdesc
124
+ @name = name
125
+ @type = type
126
+ @typedef = typedef
127
+ @len = len
128
+ @ulen = ulen
129
+ @decimals = decimals
130
+ @value = nil
131
+ #$stderr.print "initilised parameter(#{@name}): #{self.inspect}\n"
132
+ end
133
+
134
+ # method_missing is used to pass on any method call to a parameter
135
+ # to the underlying native Ruby data type
136
+ def method_missing(methid, *rest, &block)
137
+ meth = methid.id2name
138
+ #$stderr.print "method_missing: #{meth}\n"
139
+ #$stderr.print "parameters: #{@parameters.keys.inspect}\n"
140
+ if block
141
+ @value.send(meth, &block)
142
+ else
143
+ #$stderr.print "Export method_missing - no block: #{meth}\n"
144
+ @value.send(meth, *rest)
145
+ end
146
+ end
147
+
148
+ # value setting for parameters - does basic Type checking to preserve
149
+ # sanity for the underlying C extension
150
+ def value=(val=nil)
151
+ #$stderr.print "setting: #{@name} type: #{@type} value: #{val}/#{val.class}\n"
152
+ case @type
153
+ when SAPNW::RFC::INT, SAPNW::RFC::INT2, SAPNW::RFC::INT1
154
+ unless val.is_a?(Fixnum)
155
+ raise TypeError, "Must be Fixnum for INT, INT1, and INT2 (#{@name}/#{@type}/#{val.class})\n"
156
+ end
157
+ when SAPNW::RFC::NUM
158
+ unless val.is_a?(String)
159
+ raise TypeError, "Must be String for NUMC (#{@name}/#{@type}/#{val.class})\n"
160
+ end
161
+ when SAPNW::RFC::BCD
162
+ unless val.is_a?(Float) || val.is_a?(Fixnum) || val.is_a?(Bignum)
163
+ raise TypeError, "Must be FLoat or *NUM for BCD (#{@name}/#{@type}/#{val.class})\n"
164
+ end
165
+ val = val.to_s
166
+ when SAPNW::RFC::FLOAT
167
+ unless val.is_a?(Float)
168
+ raise TypeError, "Must be FLoat for FLOAT (#{@name}/#{@type}/#{val.class})\n"
169
+ end
170
+ when SAPNW::RFC::STRING, SAPNW::RFC::XSTRING
171
+ unless val.is_a?(String)
172
+ raise TypeError, "Must be String for STRING, and XSTRING (#{@name}/#{@type}/#{val.class})\n"
173
+ end
174
+ when SAPNW::RFC::BYTE
175
+ unless val.is_a?(String)
176
+ raise TypeError, "Must be String for BYTE (#{@name}/#{@type}/#{val.class})\n"
177
+ end
178
+ when SAPNW::RFC::CHAR, SAPNW::RFC::DATE, SAPNW::RFC::TIME
179
+ unless val.is_a?(String)
180
+ raise TypeError, "Must be String for CHAR, DATE, and TIME (#{@name}/#{@type}/#{val.class})\n"
181
+ end
182
+ when SAPNW::RFC::TABLE
183
+ unless val.is_a?(Array)
184
+ raise TypeError, "Must be Array for table value (#{@name}/#{val.class})\n"
185
+ end
186
+ cnt = 0
187
+ val.each do |row|
188
+ cnt += 1
189
+ unless row.is_a?(Hash)
190
+ raise TypeError, "Must be Hash for table row value (#{@name}/#{cnt}/#{row.class})\n"
191
+ end
192
+ end
193
+ when SAPNW::RFC::STRUCTURE
194
+ unless val.is_a?(Hash)
195
+ raise TypeError, "Must be a Hash for a Structure Type (#{@name}/#{@type}/#{val.class})\n"
196
+ end
197
+ else # anything - barf
198
+ raise "unknown SAP data type (#{@name}/#{@type})\n"
199
+ end
200
+ @value = val
201
+ return val
202
+ end
203
+
204
+ end
205
+
206
+ # RFC Import Parameters
207
+ class Import < SAPNW::RFC::Parameter
208
+ def initialize(*args)
209
+ @direction = SAPNW::RFC::IMPORT
210
+ super
211
+ end
212
+ end
213
+
214
+ # RFC Export Parameters
215
+ class Export < SAPNW::RFC::Parameter
216
+ def initialize(*args)
217
+ @direction = SAPNW::RFC::EXPORT
218
+ super
219
+ end
220
+ end
221
+
222
+ # RFC Changing Parameters
223
+ class Changing < SAPNW::RFC::Parameter
224
+ def initialize(*args)
225
+ @direction = SAPNW::RFC::CHANGING
226
+ super
227
+ end
228
+ end
229
+
230
+ # RFC Table type Parameters
231
+ class Table < SAPNW::RFC::Parameter
232
+ def initialize(*args)
233
+ @direction = SAPNW::RFC::TABLES
234
+ super
235
+ end
236
+
237
+ # returns the no. of rows currently in the table
238
+ def length
239
+ return @value.length
240
+ end
241
+
242
+ # assign an Array, of rows represented by Hashes to the value of
243
+ # the Table parameter.
244
+ def value=(val=[])
245
+ unless val.is_a?(Array)
246
+ raise TypeError, "Must be Array for table value (#{@name}/#{val.class})\n"
247
+ end
248
+ cnt = 0
249
+ val.each do |row|
250
+ cnt += 1
251
+ unless row.is_a?(Hash)
252
+ raise TypeError, "Must be Hash for table row value (#{@name}/#{cnt}/#{row.class})\n"
253
+ end
254
+ end
255
+ @value = val
256
+ end
257
+
258
+ # Yields each row of the table to passed Proc
259
+ def each
260
+ return nil unless @value
261
+ @value.each do |row|
262
+ yield row
263
+ end
264
+ end
265
+ end
266
+
267
+ class Type
268
+
269
+ attr_reader :name, :type, :len, :ulen, :decimals, :fields
270
+
271
+ def initialize(*args)
272
+ args = args.first if args.class == Array and args.first.class == Hash
273
+ case args
274
+ when Array
275
+ name, type, len, ulen, decimals, fields = args
276
+ when Hash
277
+ raise "Missing Type :name => #{args.inspect}\n" unless args.has_key?(:name)
278
+ raise "Missing Type :type => #{args.inspect}\n" unless args.has_key?(:type)
279
+ #raise "Missing Type :len => #{args.inspect}\n" unless args.has_key?(:len)
280
+ case args[:type]
281
+ when SAPNW::RFC::CHAR, SAPNW::RFC::DATE, SAPNW::RFC::BCD, SAPNW::RFC::TIME, SAPNW::RFC::BYTE, SAPNW::RFC::TABLE, SAPNW::RFC::NUM, SAPNW::RFC::FLOAT, SAPNW::RFC::INT, SAPNW::RFC::INT2, SAPNW::RFC::INT1, SAPNW::RFC::NULL, SAPNW::RFC::STRUCTURE, SAPNW::RFC::DECF16, SAPNW::RFC::DECF34, SAPNW::RFC::XMLDATA, SAPNW::RFC::STRING, SAPNW::RFC::XSTRING, SAPNW::RFC::EXCEPTION
282
+ else
283
+ raise "Invalid SAPNW::RFC* type supplied (#{args[:type]})\n"
284
+ end
285
+ len = 0
286
+ ulen = 0
287
+ decimals = 0
288
+ name = args[:name]
289
+ type = args[:type]
290
+ len = args[:len] if args.has_key?(:len)
291
+ ulen = 2 * len
292
+ ulen = args[:ulen] if args.has_key?(:ulen)
293
+ decimals = args[:decimals] if args.has_key?(:decimals)
294
+ fields = args[:fields] if args.has_key?(:fields)
295
+ else
296
+ raise "invalid parameters in SAPNW::RFC::Type: #{args.inspect}\n"
297
+ end
298
+ @name = name
299
+ @type = type
300
+ @len = len
301
+ @ulen = ulen
302
+ @decimals = decimals
303
+ if fields
304
+ raise "Fields must be an Array (#{fields.inspect})\n" unless fields.class == Array
305
+ slen = 0
306
+ sulen = 0
307
+ fields.each do |val|
308
+ raise "each field definition must be a Hash (#{val.inspect})\n" unless val.class == Hash
309
+ unless val.has_key?(:name) and
310
+ val.has_key?(:type) and
311
+ val.has_key?(:len)
312
+ raise "each field definition must have :name, :type, and :len (#{val.inspect})\n"
313
+ end
314
+ val[:ulen] = val[:len] * 2 unless val.has_key?(:ulen)
315
+ val[:decimals] = 0 unless val.has_key?(:decimals)
316
+ slen += val[:len]
317
+ sulen += val[:ulen]
318
+ # sort out nested types
319
+ if val[:type].class == SAPNW::RFC::Type
320
+ val[:typedef] = val[:type]
321
+ val[:type] = val[:typedef].type
322
+ end
323
+ end
324
+ @len = slen unless @len > 0
325
+ @ulen = sulen unless @ulen > 0
326
+ end
327
+ @fields = fields
328
+ #$stderr.print "initilised Type(#{name}): #{type} - #{@fields.inspect}\n"
329
+ end
330
+ end
331
+ end
332
+ end
@@ -0,0 +1,151 @@
1
+ # SAPNW is Copyright (c) 2006-2008 Piers Harding. It is free software, and
2
+ # may be redistributed under the terms specified in the README file of
3
+ # the Ruby distribution.
4
+ #
5
+ # Author:: Piers Harding <piers@ompka.net>
6
+ # Requires:: Ruby 1.9 or later
7
+ #
8
+
9
+ module SAPNW
10
+
11
+ module Servers
12
+
13
+ class << SAPNW::Base
14
+
15
+ # registers with an R/3 systems gateway service. Uses parameters supplied
16
+ # in the YAML config file by default, but overrides these with any passed
17
+ # as a Hash. returns a SAPNW::RFC::Server object
18
+ def rfc_register(args = nil)
19
+ parms = {}
20
+ parms[:trace] = self.config['trace'].to_i if self.config.key? 'trace'
21
+ parms[:tpname] = self.config['tpname'] if self.config.key? 'tpname'
22
+ parms[:gwhost] = self.config['gwhost'] if self.config.key? 'gwhost'
23
+ parms[:gwserv] = self.config['gwserv'] if self.config.key? 'gwserv'
24
+ SAP_LOGGER.debug("[" + self.name + "] base parameters to be passed are: " + parms.inspect)
25
+
26
+ case args
27
+ when nil
28
+ when Hash
29
+ parms[:trace] = args[:trace].to_i if args.key? :trace
30
+ parms[:tpname] = args[:tpname] if args.key? :tpname
31
+ parms[:gwhost] = args[:gwhost] if args.key? :gwhost
32
+ parms[:gwserv] = args[:gwserv] if args.key? :gwserv
33
+ SAP_LOGGER.debug("[" + self.name + "] with EXTRA parameters to be passed are: " + parms.inspect)
34
+ else
35
+ raise "Wrong parameters for Connection - must pass a Hash\n"
36
+ end
37
+
38
+ server = SAPNW::RFC::Server.new(parms)
39
+ SAP_LOGGER.debug("completed the server connection (#{server.handle.class}/#{server.handle.object_id}) ...")
40
+ return server
41
+ end
42
+ end
43
+ end
44
+
45
+
46
+ module RFC
47
+ class ServerException < Exception
48
+ def initialize(error=nil)
49
+ unless error.class == Hash
50
+ error = {'code' => 3, 'key' => 'RUNTIME', 'message' => error.to_s}
51
+ end
52
+ @error = error
53
+ end
54
+ end
55
+
56
+ class Server
57
+ attr_accessor :handle
58
+ attr_reader :connection_parameters, :functions
59
+
60
+ def initialize(args = nil)
61
+ @connection_parameters = []
62
+ case args
63
+ when nil
64
+ when Hash
65
+ args.each_pair { |key, val|
66
+ @connection_parameters << {'name' => key.to_s, 'value' => val.to_s}
67
+ }
68
+ else
69
+ raise "Wrong parameters for Server Connection - must pass a Hash\n"
70
+ end
71
+ SAP_LOGGER.debug("In #{self.class} initialize: #{@connection_parameters.inspect} ...")
72
+ @functions = {}
73
+ @attributes = nil
74
+ @handle = SAPNW::RFC::ServerHandle.new(self)
75
+ end
76
+
77
+ # installs a SAPNW::RFC::FunctionDescriptor object, and optionally associates
78
+ # this with a particular SysId.
79
+ def installFunction(*args)
80
+ args = args.first if args.class == Array and args.first.class == Hash
81
+ case args
82
+ when Hash
83
+ raise "Must pass an instance of SAPNW::RFC::FunctionDescriptor to installFunction()\n" unless args.has_key?(:descriptor) and args[:descriptor].class == SAPNW::RFC::FunctionDescriptor
84
+ func = args[:descriptor]
85
+ sysid = args.has_key?(:sysid) ? args[:sysid] : ""
86
+ when Array
87
+ raise "Must pass an instance of SAPNW::RFC::FunctionDescriptor to installFunction()\n" unless args.first.class == SAPNW::RFC::FunctionDescriptor
88
+ func = args.first
89
+ sysid = args.length > 1 ? args[1] : ""
90
+ else
91
+ raise "Must pass an instance of SAPNW::RFC::FunctionDescriptor to installFunction()\n"
92
+ end
93
+ #$stderr.print "sysid: #{sysid}\n"
94
+ res = func.install(sysid)
95
+ @functions[func.name] = func
96
+ return res
97
+ end
98
+
99
+ def self.handler(callback=nil, attributes=nil)
100
+ return if callback == nil
101
+ begin
102
+ return callback.call(attributes)
103
+ rescue SAPNW::RFC::ServerException => e
104
+ #$stderr.print "ServerException => #{e.error.inspect}\n"
105
+ return e
106
+ rescue StandardError => e
107
+ #$stderr.print "StandardError => #{e.inspect}/#{e.message}\n"
108
+ return SAPNW::RFC::ServerException.new({'code' => 3, 'key' => 'RUBY_RUNTIME', 'message' => e.message})
109
+ end
110
+ end
111
+
112
+
113
+ # fire the accept loop taking optionally a wait time for each loop, and a global
114
+ # callback to be triggered after each loop/loop timeout.
115
+ # Callback - if supplied - must be a Proc object, that takes a simgle parameter,
116
+ # which is a hash of the system connection attributes.
117
+ def accept(wait=120, callback=nil)
118
+ trap('INT', 'EXIT')
119
+ return @handle.accept_loop(wait, callback);
120
+ end
121
+
122
+
123
+ # similar to the accept() loop only that it does a single RfcListenAndDispatch()
124
+ # on the SAPNW::RFC::Server connection handle. The result is the RFC return code
125
+ # as per the SAPNW::RFC::RFC_* return code constants.
126
+ # process() optionally takes asingle parameter which is the wait-time.
127
+ def process(wait=120)
128
+ trap('INT', 'EXIT')
129
+ return @handle.process_loop(wait);
130
+ end
131
+
132
+ # Returns a Hash of the connections attributes of this server connection.
133
+ def connection_attributes
134
+ SAP_LOGGER.debug("In #{self.class} connection_attributes ...")
135
+ return @attributes = self.handle.connection_attributes()
136
+ end
137
+
138
+ # terminate an established RFC connection. This will invalidate any currently in-scope
139
+ # FunctionDescriptors associated with this Connection.
140
+ def close
141
+ SAP_LOGGER.debug("In #{self.class} close ...")
142
+ return nil unless self.handle
143
+ SAP_LOGGER.debug("In #{self.class} handle: #{self.handle} ...")
144
+ res = self.handle.close()
145
+ self.handle = nil
146
+ # XXX Should destroy all cached functions and structures and types tied to handle ?
147
+ return true
148
+ end
149
+ end
150
+ end
151
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sapnwrfc
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.23'
5
+ prerelease:
6
+ platform: i686-linux
7
+ authors:
8
+ - Piers Harding
9
+ autorequire:
10
+ - sapnwrfc
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-07-27 00:00:00.000000000 +02:00
14
+ default_executable:
15
+ dependencies: []
16
+ description: ! " sapnwrfc is a ruby module for performing RFC functions and BAPI
17
+ calls on\n an SAP Netweaver system NW2004+\n"
18
+ email: piers@ompka.net
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - lib/sapnwrfc/config.rb
24
+ - lib/sapnwrfc/base.rb
25
+ - lib/sapnwrfc/connection.rb
26
+ - lib/sapnwrfc/functions.rb
27
+ - lib/sapnwrfc/server.rb
28
+ - lib/sapnwrfc/parameters.rb
29
+ - lib/sapnwrfc.rb
30
+ - ext/nwsaprfc/nwsaprfc.so
31
+ has_rdoc: true
32
+ homepage: http://www.piersharding.com
33
+ licenses: []
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - ext/nwsaprfc
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: 1.9.0
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubyforge_project:
53
+ rubygems_version: 1.6.2
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: SAP Netweaver RFC connector for Ruby
57
+ test_files: []