BTP - Connect on-premise (Function module)
Here we look at the connection of a function module in the ABAP environment and how you can call it.
Table of contents
In another article we have already queried on-premise data from the backend system via OData. In this article we will take a look at the function module construct and for whom this scenario is relevant.
Introduction
When the ABAP Environment was released by SAP, many things did not yet exist and the range of functions was still very rudimentary. This also included the access methods to the backend. Access to RFC function modules was only implemented much later in order to give customers the option of continuing to use existing scenarios on the BTP.
Hint: Therefore, this technology should be used with caution as it is intended only to buy a transition to OData. So if there are CDS Views or OData that you can use, then you'd better do that.
Structure On-Premise
We use the same data that we used in the OData article. To do this, we create a function module and implement a rudimentary access logic to the data. There are two import parameters for name and branch. We then return the entries and a possible error text.
FUNCTION z_bs_demo_get_cnames
IMPORTING
VALUE(id_name) TYPE zbs_dmo_cname-name
VALUE(id_branch) TYPE zbs_dmo_cname-branch
EXPORTING
VALUE(et_cnames) TYPE zbs_t_demo_cnames
VALUE(ed_error) TYPE string.
DATA:
lt_r_name TYPE RANGE OF zbs_dmo_cname-name,
lt_r_branch TYPE RANGE OF zbs_dmo_cname-branch.
TRY.
IF id_name IS NOT INITIAL.
INSERT VALUE #( sign = 'I' option = 'CP' low = id_name ) INTO TABLE lt_r_name.
ENDIF.
IF id_branch IS NOT INITIAL.
INSERT VALUE #( sign = 'I' option = 'CP' low = id_name ) INTO TABLE lt_r_branch.
ENDIF.
SELECT FROM zbs_dmo_cname
FIELDS *
WHERE name IN @lt_r_name
AND branch IN @lt_r_branch
INTO TABLE @et_cnames.
CATCH cx_root INTO DATA(lo_error).
ed_error = lo_error->get_text( ).
ENDTRY.
ENDFUNCTION.
Metadata
Next, we also need the function module metadata, but no URL is used here since there is no public endpoint. To do this, we call transaction ACO_PROXY on the backend system and make the following settings:
In the lower area, the transaction must be set to File so that a metadata description is generated. When running the report, you will be asked for the file name and location. With this step we have extracted the metadata of the function module.
Consumption Model
Now we can create the consumption model for the function module in the ABAP environment. To do this, we select "New -> Other Repository Object" on the package ZBS_DEMO_RAP_INTERFACE via the context menu (right-click) and search for the "Service Consumption Model". Then we get to the selection dialog and fill the fields with information, whereby the mode should be set to RFC:
In the next step we enter the metadata description (path of the file) and in the next step we confirm the transport:
Corresponding objects are now generated, including the consumption model and the proxy class. The proxy class will be available for us to access later:
Read
Now we want to read the data sets and implement some example coding. To do this, we create a separate connection for RFC access via the destination and transfer this to the constructor of the proxy class. We can call the function module as a method of the class, the types are already defined in the class:
DATA(lo_destination) = cl_rfc_destination_provider=>create_by_cloud_destination( c_destination ).
NEW zbs_demo_rap_onprem_func( lo_destination )->z_bs_demo_get_cnames(
EXPORTING
id_branch = ''
id_name = ''
IMPORTING
ed_error = DATA(ld_error)
et_cnames = DATA(lt_company_names)
).
We don't pass any constraints and let the results be returned. We now output this to the console and get the following result:
The full implementation in the test class looks like this:
CLASS zcl_bs_demo_read_func DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
CONSTANTS:
c_destination TYPE string VALUE `<destination-service-id>`.
ENDCLASS.
CLASS zcl_bs_demo_read_func IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
TRY.
DATA(lo_destination) = cl_rfc_destination_provider=>create_by_cloud_destination( c_destination ).
NEW zbs_demo_rap_onprem_func( lo_destination )->z_bs_demo_get_cnames(
EXPORTING
id_branch = ''
id_name = ''
IMPORTING
ed_error = DATA(ld_error)
et_cnames = DATA(lt_company_names)
).
out->write( 'Error from backend:' ).
out->write( ld_error ).
out->write( 'Companies:' ).
out->write( lt_company_names ).
CATCH cx_root INTO DATA(lo_error).
out->write( lo_error->get_text( ) ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
Conclusion
In some places, calling an RFC function module is much clearer and easier than the OData service, but should not tempt you to only use function modules. It is an easy alternative for the transition towards OData.