sapnwrfc 0.23-i686-linux

Sign up to get free protection for your applications and to get access to all the features.
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: []