nwrfc-aphid 0.1.0

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.
@@ -0,0 +1,474 @@
1
+ # Author:: Martin Ceronio martin.ceronio@infosize.co.za
2
+ # Copyright:: Copyright (c) 2012 Martin Ceronio
3
+ # License:: MIT and/or Creative Commons Attribution-ShareAlike
4
+ # SAP, Netweaver, RFC and other names referred to in this code
5
+ # are, or may be registered trademarks and the property of SAP, AG
6
+ # No ownership over any of these is asserted by Martin Ceronio
7
+
8
+ require 'rubygems'
9
+ require 'ffi'
10
+
11
+ RUBY_VERSION_18 = RUBY_VERSION[0..2] == "1.8"
12
+ # Check if ICONV compatibility (for Ruby 1.8 and below) is required
13
+ STRING_SUPPORTS_ENCODE = ''.respond_to?(:encode) # Ruby 1.9 and onwards
14
+
15
+ require 'iconv' unless STRING_SUPPORTS_ENCODE
16
+
17
+ # Provide an alias for FFI::MemoryPointer#read_int to `read_uint` in 1.8
18
+ # See http://stackoverflow.com/questions/9035661/ruby-ffi-memorypointer-read-int-present-in-1-9-but-not-1-8
19
+ # Probably not good to interpret an unsigned int as an int, but we don't expect to use it for big values
20
+ # that could result in sign conversion
21
+ # FIXME - This must go! Replace with calls to get_* defined in FFI::MemoryPointer
22
+ if RUBY_VERSION_18
23
+ FFI::MemoryPointer.class_eval { alias :read_uint :read_int }
24
+ end
25
+
26
+ # Enhancement to FFI::Pointer to be able to read a double-null terminated string,
27
+ # which would be returned e.g. by RfcGetVersion() in the SDK
28
+ # See http://stackoverflow.com/questions/9293307/ruby-ffi-ruby-1-8-reading-utf-16le-encoded-strings
29
+ module FFI
30
+ class Pointer
31
+
32
+ # Enhancement to FFI::Pointer to be able to read a double-null terminated string,
33
+ # which would be returned e.g. by RfcGetVersion() in the SDK
34
+ # See http://stackoverflow.com/questions/9293307/ruby-ffi-ruby-1-8-reading-utf-16le-encoded-strings
35
+ # It should be safe to call this on a Pointer within the context of the NW RFC SDK library,
36
+ # because all strings are supposed to be UTF-16LE encoded and double-null terminated
37
+ def read_string_dn(max=0)
38
+ cont_nullcount = 0
39
+ offset = 0
40
+ until cont_nullcount == 2
41
+ byte = get_bytes(offset, 1)
42
+ cont_nullcount += 1 if byte == "\000"
43
+ cont_nullcount = 0 if byte != "\000"
44
+ offset += 1
45
+ end
46
+ get_bytes(0, offset+1)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Enhancement to the String class to put string values into double-null
52
+ # terminated UTF16 little endian encoded strings as required by the NW RFC
53
+ # SDK function, which should work on Linux and Windows (and maybe other
54
+ # architectures, though the plan is not to support them)
55
+ #String.class_eval{define_method(:cU){ Iconv.conv("UTF-16LE", "UTF8", self+"\0") }}
56
+
57
+ # Availability of String::convert() should indicate otherwise
58
+ if STRING_SUPPORTS_ENCODE
59
+
60
+ class String
61
+
62
+ # Convert string from UTF-8 to double-null terminated UTF-16LE string
63
+ def cU
64
+ (self.to_s + "\0").force_encoding('UTF-8').encode('UTF-16LE')
65
+ end
66
+
67
+ # Convert string from UTF-16LE to UTF-8 and trim trailing whitespace
68
+ def uC
69
+ self.force_encoding('UTF-16LE').encode('UTF-8').strip
70
+ end
71
+
72
+ end
73
+
74
+ else
75
+
76
+ class String
77
+
78
+ # Convert string from UTF-8 to doudble-null terminated UTF-16LE string
79
+ def cU
80
+ NWRFCLib::Cutf8_to_utf16le.iconv(self+"\0")
81
+ end
82
+
83
+ # Convert string from UTF-16LE to UTF-8 and trim trailing whitespace
84
+ def uC
85
+ NWRFCLib::Cutf16le_to_utf8.iconv(self).strip
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ # Enhancement to FFI::StructLayout::CharArray to add a get_str method that changes the
93
+ # string value of the character array by enforcing encoding of UTF-16LE (as used in NW RFC SDK)
94
+ # and strips off blanks at the end to return a readable String
95
+ class FFI::StructLayout::CharArray
96
+ def get_str
97
+ self.to_ptr.read_string(self.size).uC
98
+ end
99
+ end
100
+
101
+ # Enhancement for JRuby to enable the same reading of strings as above, but for JRuby we must make
102
+ # the enhancement to FFI::StructLayout::CharArrayProxy
103
+ # TODO Perhaps we should make the alternate change (above) the other branch of the following if statement
104
+ if RUBY_PLATFORM == 'java'
105
+ class FFI::StructLayout::CharArrayProxy
106
+ def get_str
107
+ self.to_ptr.read_string(self.size).uC
108
+ end
109
+ end
110
+ end
111
+
112
+ # Library wrapper around NW RFC SDK shared library using RUBY-FFI
113
+ module NWRFCLib
114
+
115
+ unless STRING_SUPPORTS_ENCODE # Ruby 1.8 and below
116
+ Cutf8_to_utf16le = Iconv.new("UTF-16LE", "UTF-8")
117
+ Cutf16le_to_utf8 = Iconv.new("UTF-8", "UTF-16LE")
118
+ end
119
+
120
+ extend FFI::Library
121
+ ffi_lib 'sapnwrfc'
122
+
123
+ # Multiplier for providing correct byte size for String passed to RFC library
124
+ #@todo Make platform-dependent size based on RUBY_PLATFORM
125
+ B_SIZE = 2
126
+
127
+ RFC_RC = enum(
128
+ :RFC_OK,
129
+ :RFC_COMMUNICATION_FAILURE,
130
+ :RFC_LOGON_FAILURE,
131
+ :RFC_ABAP_RUNTIME_FAILURE,
132
+ :RFC_ABAP_MESSAGE,
133
+ :RFC_ABAP_EXCEPTION,
134
+ :RFC_CLOSED,
135
+ :RFC_CANCELED,
136
+ :RFC_TIMEOUT,
137
+ :RFC_MEMORY_INSUFFICIENT,
138
+ :RFC_VERSION_MISMATCH,
139
+ :RFC_INVALID_PROTOCOL,
140
+ :RFC_SERIALIZATION_FAILURE,
141
+ :RFC_INVALID_HANDLE,
142
+ :RFC_RETRY,
143
+ :RFC_EXTERNAL_FAILURE,
144
+ :RFC_EXECUTED,
145
+ :RFC_NOT_FOUND,
146
+ :RFC_NOT_SUPPORTED,
147
+ :RFC_ILLEGAL_STATE,
148
+ :RFC_INVALID_PARAMETER,
149
+ :RFC_CODEPAGE_CONVERSION_FAILURE,
150
+ :RFC_CONVERSION_FAILURE,
151
+ :RFC_BUFFER_TOO_SMALL,
152
+ :RFC_TABLE_MOVE_BOF,
153
+ :RFC_TABLE_MOVE_EOF,
154
+ :RFC_UNKNOWN_ERROR
155
+ )
156
+
157
+ RFC_ERROR_GROUP = enum(
158
+ :OK,
159
+ :ABAP_APPLICATION_FAILURE,
160
+ :ABAP_RUNTIME_FAILURE,
161
+ :LOGON_FAILURE,
162
+ :COMMUNICATION_FAILURE,
163
+ :EXTERNAL_RUNTIME_FAILURE,
164
+ :EXTERNAL_APPLICATION_FAILURE
165
+ )
166
+
167
+ RFC_DIRECTION = enum(
168
+ :RFC_IMPORT, 1,
169
+ :RFC_EXPORT, 2,
170
+ :RFC_CHANGING, 3,
171
+ :RFC_TABLES, 7
172
+ )
173
+
174
+ RFC_TYPE = enum(
175
+ :RFCTYPE_CHAR, 0,
176
+ :RFCTYPE_DATE, 1,
177
+ :RFCTYPE_BCD, 2,
178
+ :RFCTYPE_TIME, 3,
179
+ :RFCTYPE_BYTE, 4,
180
+ :RFCTYPE_TABLE, 5,
181
+ :RFCTYPE_NUM, 6,
182
+ :RFCTYPE_FLOAT, 7,
183
+ :RFCTYPE_INT, 8,
184
+ :RFCTYPE_INT2, 9,
185
+ :RFCTYPE_INT1, 10,
186
+ :RFCTYPE_NULL, 14,
187
+ :RFCTYPE_ABAPOBJECT, 16,
188
+ :RFCTYPE_STRUCTURE, 17,
189
+ :RFCTYPE_DECF16, 23,
190
+ :RFCTYPE_DECF34, 24,
191
+ :RFCTYPE_XMLDATA, 28,
192
+ :RFCTYPE_STRING, 29,
193
+ :RFCTYPE_XSTRING, 30,
194
+ :RFCTYPE_BOX, 31,
195
+ :RFCTYPE_GENERIC_BOX, 32,
196
+ :_RFCTYPE_max_value
197
+ )
198
+
199
+ # Connection parameter wrapper (struct RFC_CONNECTION_PARAMETER in sapnwrfc.h)
200
+ class RFCConnParam < FFI::Struct
201
+ layout :name, :pointer,
202
+ :value, :pointer
203
+ end
204
+
205
+ # Connection Details (struct RFC_ATTRIBUTES in sapnwrfc.h)
206
+ class RFCConnection < FFI::Struct
207
+ layout :dest, [:char, (64+1)*B_SIZE],
208
+ :host, [:char, (100+1)*B_SIZE],
209
+ :partnerHost, [:char, (100+1)*B_SIZE],
210
+ :sysNumber, [:char, (2+1)*B_SIZE],
211
+ :sysId, [:char, (8+1)*B_SIZE],
212
+ :client, [:char, (3+1)*B_SIZE],
213
+ :user, [:char, (12+1)*B_SIZE],
214
+ :language, [:char, (2+1)*B_SIZE],
215
+ :trace, [:char, (1+1)*B_SIZE],
216
+ :isoLanguage, [:char, (2+1)*B_SIZE],
217
+ :codepage, [:char, (4+1)*B_SIZE],
218
+ :partnerCodepage, [:char, (4+1)*B_SIZE],
219
+ :rfcRole, [:char, (1+1)*B_SIZE],
220
+ :type, [:char, (1+1)*B_SIZE],
221
+ :partnerType, [:char, (1+1)*B_SIZE],
222
+ :rel, [:char, (4+1)*B_SIZE],
223
+ :partnerRel, [:char, (4+1)*B_SIZE],
224
+ :kernelRel, [:char, (4+1)*B_SIZE],
225
+ :cpicConvId, [:char, (8+1)*B_SIZE],
226
+ :progName, [:char, (128+1)*B_SIZE],
227
+ :reserved, [:char, (86+1)*B_SIZE]
228
+ end
229
+
230
+ # Error info wrapper (struct RFC_ERROR_INFO in sapnwrfc.h)
231
+ class RFCError < FFI::Struct
232
+ layout :code, :int,
233
+ :group, :int,
234
+ :key, [:char, (128)*B_SIZE],
235
+ :message, [:char, (512)*B_SIZE],
236
+ :abapMsgClass, [:char, (20+1)*B_SIZE],
237
+ :abapMsgType, [:char, (1+1)*B_SIZE],
238
+ :abapMsgNumber, [:char, (3+1)*B_SIZE],
239
+ :abapMsgV1, [:char, (50+1)*B_SIZE],
240
+ :abapMsgV2, [:char, (50+1)*B_SIZE],
241
+ :abapMsgV3, [:char, (50+1)*B_SIZE],
242
+ :abapMsgV4, [:char, (50+1)*B_SIZE]
243
+ end
244
+
245
+ # Function Parameter Description (struct RFC_PARAMETER_DESC in sapnwrfc.h)
246
+ class RFCFuncParam < FFI::Struct
247
+ layout :name, [:char, (30+1)*B_SIZE],
248
+ :type, :int, #enum RFCTYPE
249
+ :direction, :int, #enum RFC_DIRECTION
250
+ :nucLength, :uint,
251
+ :ucLength, :uint,
252
+ :decimals, :uint,
253
+ :typeDescHandle, :pointer, #RFC_TYPE_DESC_HANDLE
254
+ :defaultValue, [:char, (30+1)*B_SIZE], #RFC_PARAMETER_DEFVALUE
255
+ :parameterText, [:char, (79+1)*B_SIZE], #RFC_PARAMETER_TEXT
256
+ :optional, :uchar, #RFC_BYTE
257
+ :extendedDescription, :pointer
258
+ end
259
+
260
+ class RFCFieldDesc < FFI::Struct
261
+ layout :name, [:char, (30+1)*B_SIZE],
262
+ :type, :int, #enum RFCTYPE
263
+ :nucLength, :uint,
264
+ :nucOffset, :uint,
265
+ :ucLength, :uint,
266
+ :ucOffset, :uint,
267
+ :decimals, :uint,
268
+ :typeDescHandle, :pointer, #RFC_TYPE_DESC_HANDLE
269
+ :extendedDescription, :pointer
270
+ end
271
+
272
+ class RFCDataContainer < FFI::Struct
273
+ layout :handle, :pointer
274
+ end
275
+
276
+ # typedef :RFCDataContainer, RFCStructureHandle
277
+ # typedef :RFCDataContainer, RFCTableHandle
278
+
279
+ class RFC_FUNCTION_DESC_HANDLE < FFI::Struct
280
+ layout :handle, :pointer
281
+ end
282
+
283
+ class RFC_TYPE_DESC_HANDLE < FFI::Struct
284
+ layout :handle, :pointer
285
+ end
286
+
287
+ class DATA_CONTAINER_HANDLE < FFI::Struct
288
+ layout :handle, :pointer
289
+ end
290
+
291
+ class RFC_DECF16 < FFI::Union
292
+ layout :bytes, [:uchar, 8],
293
+ :align, :double
294
+ end
295
+
296
+ # class SAP_MAX_ALIGN_T < FFI::Union
297
+ # layout :align1, :long,
298
+ # :align2, :double,
299
+ # :align3, :pointer,
300
+ # :align4,
301
+ # end
302
+
303
+ # class RFC_DECF34 < FFI::Union
304
+ # layout :bytes, [:uchar, 16],
305
+ # :align, 16
306
+ # end
307
+
308
+ #############################################################################################################
309
+ # ATTACH FUNCTIONS
310
+ # The functions here were obtained by parsing content from the doxygen files from the documentation
311
+ # accompanying the NW RFC SDK, and were tweaked here and there afterward. Most of them are actually not
312
+ # yet used in our NWRFC library, so calling them may not work. For best results, consult sapnwrfc.h from
313
+ # the SDK
314
+ #############################################################################################################
315
+ # Callback for function server (function implementation)
316
+ callback :funcimpl, [:pointer, :pointer, :pointer], :int
317
+
318
+ # Function mappings
319
+ [
320
+ [:add_exception, :RfcAddException, [:pointer, :pointer, :pointer], :int],
321
+ [:add_function_desc, :RfcAddFunctionDesc, [:pointer, :pointer, :pointer], :int],
322
+ [:add_parameter, :RfcAddParameter, [:pointer, :pointer, :pointer], :int],
323
+ [:add_type_desc, :RfcAddTypeDesc, [:pointer, :pointer, :pointer], :int],
324
+ [:add_type_field, :RfcAddTypeField, [:pointer, :pointer, :pointer], :int],
325
+ # @method append_new_row(table_handle, error_handle)
326
+ # @returns FFI::Pointer pointer to structure of new row
327
+ # calls RfcAppendNewRow()
328
+ [:append_new_row, :RfcAppendNewRow, [:pointer, :pointer], :pointer],
329
+ # @method append_row(table_handle, structure, error_handle)
330
+ # @returns Integer RC
331
+ # calls RfcAppendRow()
332
+ [:append_row, :RfcAppendRow, [:pointer, :pointer, :pointer], :int],
333
+ [:clone_structure, :RfcCloneStructure, [:pointer, :pointer], :pointer],
334
+ [:clone_table, :RfcCloneTable, [:pointer, :pointer], :pointer],
335
+ [:close_connection, :RfcCloseConnection, [:pointer, :pointer], :int],
336
+ [:confirm_transaction, :RfcConfirmTransaction, [:pointer, :pointer], :int],
337
+ [:create_function, :RfcCreateFunction, [:pointer, :pointer], :pointer],
338
+ [:create_function_desc, :RfcCreateFunctionDesc, [:pointer, :pointer], :pointer],
339
+ [:create_structure, :RfcCreateStructure, [:pointer, :pointer], :pointer],
340
+ [:create_table, :RfcCreateTable, [:pointer, :pointer], :pointer],
341
+ [:create_transaction, :RfcCreateTransaction, [:pointer, :pointer, :pointer, :pointer], :pointer],
342
+ [:create_type_desc, :RfcCreateTypeDesc, [:pointer, :pointer], :pointer],
343
+ [:delete_all_rows, :RfcDeleteAllRows, [:pointer, :pointer], :int],
344
+ [:delete_current_row, :RfcDeleteCurrentRow, [:pointer, :pointer], :int],
345
+ [:describe_function, :RfcDescribeFunction, [:pointer, :pointer], :pointer],
346
+ [:describe_type, :RfcDescribeType, [:pointer, :pointer], :pointer],
347
+ [:destroy_function, :RfcDestroyFunction, [:pointer, :pointer], :int],
348
+ [:destroy_function_desc, :RfcDestroyFunctionDesc, [:pointer, :pointer], :int],
349
+ [:destroy_structure, :RfcDestroyStructure, [:pointer, :pointer], :int],
350
+ [:destroy_table, :RfcDestroyTable, [:pointer, :pointer], :int],
351
+ [:destroy_transaction, :RfcDestroyTransaction, [:pointer, :pointer], :int],
352
+ [:destroy_type_desc, :RfcDestroyTypeDesc, [:pointer, :pointer], :int],
353
+ [:enable_basxml, :RfcEnableBASXML, [:pointer, :pointer], :int],
354
+ [:get_bytes, :RfcGetBytes, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
355
+ [:get_cached_function_desc, :RfcGetCachedFunctionDesc, [:pointer, :pointer, :pointer], :pointer],
356
+ [:get_cached_type_desc, :RfcGetCachedTypeDesc, [:pointer, :pointer, :pointer], :pointer],
357
+ [:get_chars, :RfcGetChars, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
358
+ [:get_connection_attributes, :RfcGetConnectionAttributes, [:pointer, :pointer, :pointer], :int],
359
+ [:get_current_row, :RfcGetCurrentRow, [:pointer, :pointer], :pointer],
360
+ [:get_date, :RfcGetDate, [:pointer, :pointer, :pointer, :pointer], :int],
361
+ [:get_dec_f16, :RfcGetDecF16, [:pointer, :pointer, :pointer, :pointer], :int],
362
+ [:get_dec_f34, :RfcGetDecF34, [:pointer, :pointer, :pointer, :pointer], :int],
363
+ [:get_direction_as_string, :RfcGetDirectionAsString, [:pointer], :pointer],
364
+ [:get_exception_count, :RfcGetExceptionCount, [:pointer, :pointer, :pointer], :int],
365
+ [:get_exception_desc_by_index, :RfcGetExceptionDescByIndex, [:pointer, :uint, :pointer, :pointer], :int],
366
+ [:get_exception_desc_by_name, :RfcGetExceptionDescByName, [:pointer, :pointer, :pointer, :pointer], :int],
367
+ [:get_field_count, :RfcGetFieldCount, [:pointer, :pointer, :pointer], :int],
368
+ [:get_field_desc_by_index, :RfcGetFieldDescByIndex, [:pointer, :uint, :pointer, :pointer], :int],
369
+ [:get_field_desc_by_name, :RfcGetFieldDescByName, [:pointer, :pointer, :pointer, :pointer], :int],
370
+ [:get_float, :RfcGetFloat, [:pointer, :pointer, :pointer, :pointer], :int],
371
+ [:get_function_desc, :RfcGetFunctionDesc, [:pointer, :pointer, :pointer], :pointer],
372
+ [:get_function_name, :RfcGetFunctionName, [:pointer, :pointer, :pointer], :int],
373
+ [:get_int, :RfcGetInt, [:pointer, :pointer, :pointer, :pointer], :int],
374
+ [:get_int1, :RfcGetInt1, [:pointer, :pointer, :pointer, :pointer], :int],
375
+ [:get_int2, :RfcGetInt2, [:pointer, :pointer, :pointer, :pointer], :int],
376
+ [:get_num, :RfcGetNum, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
377
+ [:get_parameter_count, :RfcGetParameterCount, [:pointer, :pointer, :pointer], :int],
378
+ [:get_parameter_desc_by_index, :RfcGetParameterDescByIndex, [:pointer, :uint, :pointer, :pointer], :int],
379
+ [:get_parameter_desc_by_name, :RfcGetParameterDescByName, [:pointer, :pointer, :pointer, :pointer], :int],
380
+ [:get_partner_snc_key, :RfcGetPartnerSNCKey, [:pointer, :pointer, :pointer, :pointer], :int],
381
+ [:get_partner_snc_name, :RfcGetPartnerSNCName, [:pointer, :pointer, :uint, :pointer], :int],
382
+ [:get_partner_sso_ticket, :RfcGetPartnerSSOTicket, [:pointer, :pointer, :pointer, :pointer], :int],
383
+ [:get_rc_as_string, :RfcGetRcAsString, [:pointer], :pointer],
384
+ [:get_row_count, :RfcGetRowCount, [:pointer, :pointer, :pointer], :int],
385
+ [:get_string, :RfcGetString, [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :int],
386
+ [:get_string_length, :RfcGetStringLength, [:pointer, :pointer, :pointer, :pointer], :int],
387
+ [:get_structure, :RfcGetStructure, [:pointer, :pointer, :pointer, :pointer], :int],
388
+ [:get_table, :RfcGetTable, [:pointer, :pointer, :pointer, :pointer], :int],
389
+ [:get_time, :RfcGetTime, [:pointer, :pointer, :pointer, :pointer], :int],
390
+ [:get_transaction_id, :RfcGetTransactionID, [:pointer, :pointer, :pointer], :int],
391
+ [:get_type_as_string, :RfcGetTypeAsString, [:pointer], :pointer],
392
+ [:get_type_desc, :RfcGetTypeDesc, [:pointer, :pointer, :pointer], :pointer],
393
+ [:get_type_length, :RfcGetTypeLength, [:pointer, :pointer, :pointer, :pointer], :int],
394
+ [:get_type_name, :RfcGetTypeName, [:pointer, :pointer, :pointer], :int],
395
+ [:get_version, :RfcGetVersion, [:pointer, :pointer, :pointer], :pointer],
396
+ [:get_x_string, :RfcGetXString, [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :int],
397
+ [:init, :RfcInit, [:pointer], :int],
398
+ [:insert_new_row, :RfcInsertNewRow, [:pointer, :pointer], :pointer],
399
+ [:insert_row, :RfcInsertRow, [:pointer, :pointer, :pointer], :int],
400
+ [:install_generic_server_function, :RfcInstallGenericServerFunction, [:pointer, :pointer, :pointer], :int],
401
+ [:install_server_function, :RfcInstallServerFunction, [:pointer, :pointer, :funcimpl, :pointer], :int],
402
+ [:install_transaction_handlers, :RfcInstallTransactionHandlers, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int],
403
+ [:invoke, :RfcInvoke, [:pointer, :pointer, :pointer], :int],
404
+ [:invoke_in_transaction, :RfcInvokeInTransaction, [:pointer, :pointer, :pointer], :int],
405
+ [:is_basxml_supported, :RfcIsBASXMLSupported, [:pointer, :pointer, :pointer], :int],
406
+ #[:is_connection_handle_valid, :RfcIsConnectionHandleValid, [:pointer, :pointer, :pointer], :int],
407
+ [:is_parameter_active, :RfcIsParameterActive, [:pointer, :pointer, :pointer, :pointer], :int],
408
+ [:listen_and_dispatch, :RfcListenAndDispatch, [:pointer, :int, :pointer], :int],
409
+ [:move_to, :RfcMoveTo, [:pointer, :uint, :pointer], :int],
410
+ [:move_to_first_row, :RfcMoveToFirstRow, [:pointer, :pointer], :int],
411
+ [:move_to_last_row, :RfcMoveToLastRow, [:pointer, :pointer], :int],
412
+ [:move_to_next_row, :RfcMoveToNextRow, [:pointer, :pointer], :int],
413
+ [:move_to_previous_row, :RfcMoveToPreviousRow, [:pointer, :pointer], :int],
414
+ [:open_connection, :RfcOpenConnection, [:pointer, :uint, :pointer], :pointer],
415
+ [:ping, :RfcPing, [:pointer, :pointer], :int],
416
+ [:register_server, :RfcRegisterServer, [:pointer, :uint, :pointer], :pointer],
417
+ [:reload_ini_file, :RfcReloadIniFile, [:pointer], :int],
418
+ # [:remove_function_desc, :RfcRemoveFunctionDesc, [:pointer, :pointer, :pointer], :int],
419
+ # [:remove_type_desc, :RfcRemoveTypeDesc, [:pointer, :pointer, :pointer], :int],
420
+ [:reset_server_context, :RfcResetServerContext, [:pointer, :pointer], :int],
421
+ [:sapuc_to_utf8, :RfcSAPUCToUTF8, [:pointer, :uint, :pointer, :pointer, :pointer, :pointer], :int],
422
+ [:set_bytes, :RfcSetBytes, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
423
+ [:set_chars, :RfcSetChars, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
424
+ [:set_date, :RfcSetDate, [:pointer, :pointer, :pointer, :pointer], :int],
425
+ #[:set_dec_f16, :RfcSetDecF16, [:pointer, :pointer, :pointer, :pointer], :int],
426
+ [:set_dec_f16, :RfcSetDecF16, [:pointer, :pointer, RFC_DECF16.by_value, :pointer], :int],
427
+ [:set_dec_f34, :RfcSetDecF34, [:pointer, :pointer, :pointer, :pointer], :int],
428
+ [:set_float, :RfcSetFloat, [:pointer, :pointer, :double, :pointer], :int],
429
+ [:set_ini_path, :RfcSetIniPath, [:pointer, :pointer], :int],
430
+ [:set_int, :RfcSetInt, [:pointer, :pointer, :long, :pointer], :int],
431
+ [:set_int1, :RfcSetInt1, [:pointer, :pointer, :uint8, :pointer], :int],
432
+ [:set_int2, :RfcSetInt2, [:pointer, :pointer, :short, :pointer], :int],
433
+ [:set_num, :RfcSetNum, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
434
+ [:set_parameter_active, :RfcSetParameterActive, [:pointer, :pointer, :int, :pointer], :int],
435
+ [:set_string, :RfcSetString, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
436
+ [:set_structure, :RfcSetStructure, [:pointer, :pointer, :pointer, :pointer], :int],
437
+ [:set_table, :RfcSetTable, [:pointer, :pointer, :pointer, :pointer], :int],
438
+ [:set_time, :RfcSetTime, [:pointer, :pointer, :pointer, :pointer], :int],
439
+ #[:set_trace_dir, :RfcSetTraceDir, [:pointer, :pointer], :int],
440
+ #[:set_trace_encoding, :RfcSetTraceEncoding, [:pointer, :pointer], :int],
441
+ #[:set_trace_level, :RfcSetTraceLevel, [:pointer, :pointer, :uint, :pointer], :int],
442
+ [:set_type_length, :RfcSetTypeLength, [:pointer, :uint, :uint, :pointer], :int],
443
+ [:set_x_string, :RfcSetXString, [:pointer, :pointer, :pointer, :uint, :pointer], :int],
444
+ [:snc_key_to_name, :RfcSNCKeyToName, [:pointer, :pointer, :uint, :pointer, :uint, :pointer], :int],
445
+ [:snc_name_to_key, :RfcSNCNameToKey, [:pointer, :pointer, :pointer, :pointer, :pointer], :int],
446
+ [:start_server, :RfcStartServer, [:int, :pointer, :pointer, :uint, :pointer], :pointer],
447
+ [:submit_transaction, :RfcSubmitTransaction, [:pointer, :pointer], :int],
448
+ [:utf8_to_sapuc, :RfcUTF8ToSAPUC, [:pointer, :uint, :pointer, :pointer, :pointer, :pointer], :int]
449
+ ].each { |funcsig|
450
+ attach_function(funcsig[0], funcsig[1], funcsig[2], funcsig[3], :blocking => true)
451
+ }
452
+
453
+ # Take Hash of connection parameters and returns FFI pointer to an array
454
+ # for passing to connection
455
+ # ---
456
+ # TODO - Ideally, this method should live in nwrfc.rb
457
+ def NWRFCLib.make_conn_params(params) #https://github.com/ffi/ffi/wiki/Structs
458
+ par = FFI::MemoryPointer.new(RFCConnParam, params.length)
459
+ pars = params.length.times.collect do |i|
460
+ RFCConnParam.new(par + i * RFCConnParam.size)
461
+ end
462
+ #TODO Optimize this method
463
+ tpar = params.to_a
464
+ params.length.times do |n|
465
+ # str = (tpar[n][0].to_s + "\0").encode("UTF-16LE")
466
+ pars[n][:name] = FFI::MemoryPointer.from_string(tpar[n][0].to_s.cU)
467
+ # str = (tpar[n][1].to_s + "\0").encode("UTF-16LE")
468
+ # str = str.encode("UTF-16LE")
469
+ pars[n][:value] = FFI::MemoryPointer.from_string(tpar[n][1].to_s.cU)
470
+ end
471
+ par
472
+ end
473
+
474
+ end
@@ -0,0 +1,48 @@
1
+ module NWRFC
2
+
3
+ # Implementation of a server to host RFC functions to be called from an ABAP system
4
+ class Server
5
+
6
+ TIMEOUT = 0
7
+
8
+ # Register a server with the given gateway and program ID
9
+ def initialize(params)
10
+ raise "Rarameters must be a Hash" unless params.instance_of? Hash
11
+ @rparams = NWRFC.make_conn_params(params)
12
+ raise "Could not create valid pointer from parameters" unless @rparams.instance_of? FFI::MemoryPointer
13
+ @error = NWRFCLib::RFCError.new
14
+ @handle = NWRFCLib.register_server(@rparams, params.size, @error)
15
+ NWRFC.check_error(@error)
16
+ end
17
+
18
+
19
+ # Start serving an RFC function, given the definition and the block,
20
+ # to which the connection and functions are yielded
21
+ def serve(function, &block)
22
+ # Establish callback handler
23
+ callback = Proc.new do |connection, function_handle, error|
24
+ function_call = FunctionCall.new(function_handle)
25
+ yield(function_call)
26
+ end
27
+ rc = NWRFCLib.install_server_function(nil, function.desc, callback, @error)
28
+ NWRFC.check_error(@error) if rc > 0
29
+
30
+ # Server loop
31
+ while (rc==NWRFCLib::RFC_RC[:RFC_OK] || rc==NWRFCLib::RFC_RC[:RFC_RETRY] || rc==NWRFCLib::RFC_RC[:RFC_ABAP_EXCEPTION])
32
+ rc = NWRFCLib.listen_and_dispatch(@handle, TIMEOUT, @error)
33
+ end
34
+ end
35
+
36
+ # Disconnect from the server
37
+ def disconnect
38
+ return unless @handle
39
+ rc = NWRFCLib.close_connection(@handle, @error)
40
+ NWRFC.check_error(@error) if rc > 0
41
+ @handle = nil
42
+ end
43
+
44
+ alias :close :disconnect
45
+
46
+ end
47
+
48
+ end