BTP - Anbindung On-Premise (OData)
In diesem Artikel schauen wir uns an, wie wir eine On-Premise OData Schnittstelle ans ABAP Environment anbinden und aufrufen können.
Inhaltsverzeichnis
Das ABAP Environment ist eine Entwicklungsumgebung, die kaum über eigene Daten verfügt und sich die Daten aus den anderen Systemen nachlesen muss. In diesem Artikel werden wir eine Schnittstelle per RAP On-Premise entwickeln und als OData v2 API zur Verfügung stellen. In der BTP werden wir dann die Daten konsumieren.
UPDATE (15.12.23):
- Mittlerweile wurde ein neues Consumption Model (v2) zur Verfügung gestellt, der Update des Artikels findest über den Link.
- Änderungen wurden in der Generierung des Models gemacht, andere Punkte des Artikels sind noch aktuell.
Aufbau On-Premise
Schauen wir uns im ersten Schritt einmal die Schnittstelle On-Premise an. Dazu definieren wir eine Tabelle mit Namen von Partnern die wir auch in unserer Partner App in der RAP Serie verwenden. Name wird dabei zum Schlüssel und wir definieren Zusatzinformationen, wie Branche und Beschreibung.
@EndUserText.label : 'Company Names'
@AbapCatalog.tableCategory : #TRANSPARENT
define table zbs_dmo_cname {
key client : abap.clnt not null;
key name : abap.char(60) not null;
branch : abap.char(50);
description : abap.char(255);
}
Im nächsten Schritt generieren wir den RAP Stack auf die Tabelle, das bedeutet wir legen die Core Data Services und die Verhaltensimplementierung an. Die Verhaltensdefinition sieht dabei wir folgt aus:
managed implementation in class zbp_demo_company_name unique;
strict;
define behavior for ZBS_I_DmoCName alias Name
persistent table zbs_dmo_cname
lock master
authorization master ( instance )
{
create;
update;
delete;
mapping for zbs_dmo_cname
{
CompanyName = name;
Branch = branch;
CompanyDescription = description;
}
}
Auf dem Stack generieren wir eine OData v2 Web API, um die Daten zur Verfügung zu stellen. Annotationen benötigen die Core Data Services dabei nicht, da wir nur eine Schnittstelle und keine Ausgabe benötigen:
Wie du eine einfach RAP Anwendung aufbaust, findest du hier in der Übersicht. Wie die Schnittstelle On-Premise aufgebaut ist und was noch alles zur Schnittstelle gehört, kannst du im Repository finden.
Daten
Die Tabelle befüllen wir zusätzlich noch mit Daten, dies machen wir über eine ausführbare Klasse und eine statische Methode, um diese auch wiederverwendbar zu machen. Die Klasse findest du auch im On-Premse Repositry:
CLASS zcl_bs_demo_rebuild_intf_data DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
CLASS-METHODS:
rebuild_data.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_bs_demo_rebuild_intf_data IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
zcl_bs_demo_rebuild_intf_data=>rebuild_data( ).
ENDMETHOD.
METHOD rebuild_data.
DATA:
lt_names TYPE SORTED TABLE OF zbs_dmo_cname WITH UNIQUE KEY name.
lt_names = VALUE #(
( name = 'SAP'
branch = 'Software'
description = 'SAP SE is a German multinational software company based in Walldorf, Baden-Württemberg. It develops enterprise software to manage business operations and customer relations.' )
( name = 'Microsoft'
branch = 'Software'
description = 'Microsoft Corporation is an American multinational technology corporation producing computer software, consumer electronics, personal computers, and related services.' )
( name = 'BMW'
branch = 'Automotive Industry'
description = 'Bayerische Motoren Werke AG, abbreviated as BMW, is a German multinational manufacturer of luxury vehicles and motorcycles headquartered in Munich, Bavaria.' )
( name = 'Nestle'
branch = 'Food'
description = 'Nestlé S.A. is a Swiss multinational food and drink processing conglomerate corporation headquartered in Vevey, Vaud, Switzerland.' )
( name = 'Amazon'
branch = 'Online Trade'
description = 'Amazon.com, Inc. is an American multinational technology company focusing on e-commerce, cloud computing, online advertising, digital streaming, and artificial intelligence.' )
).
INSERT zbs_dmo_cname FROM TABLE lt_names.
COMMIT WORK.
ENDMETHOD.
ENDCLASS.
Der Inhalt der Tabelle sieht im Anschluss wie folgt aus (Data Preview in Eclipse):
Metadaten
Nachdem wir nun die Schnittstelle fertig gestellt haben und der Endpunkt On-Premise aufrufbar ist, benötigen wir nun für das ABAP Environment die Metadaten der Schnittstelle. Der einfachste Weg läuft über die URL die du über das Service Bindung aufrufen kannst:
Es wird dein Browser aufgerufen und der Service angezeigt, du erhältst die ersten Informationen des OData Service als XML angezeigt:
Nun musst du nur noch "$metadata" am Ende der URL ergänzen, dann wird die Metadatei des Service angezeigt, die du dann einfach per Rechts-Klick und "Speichern unter" als XML-Datei ablegen kannst:
Die XML Datei benötigen wir nun für die folgenden Schritte im ABAP Environment.
Consumption Model
Die Entwicklung On-Premise ist nun so weit abgeschlossen und wir können mit der Anbindung im ABAP Environment beginnen. Dazu legen wir ein neues Paket ZBS_DEMO_RAP_INTERFACE in unserem RAP Projekt an. Dann kannst du einen Rechts-Klick auf das Paket machen und über "New -> Other Repository Object" nach "Consumption Model" suchen. Diese Art von Objekt wollen wir nun anlegen, um automatische alle Objekte für den Zugriff zu erhalten.
Die neue Komponente sollte schon dem richtigen Paket zugeordnet sein, neben dem Namen und der Beschreibung, müssen wir noch den Typ von RFC auf OData anpassen:
Jetzt geben wir den Pfad zur Metadaten Datei an und bestimmen noch einen Präfix, der für alle Objekte genommen wird. Da "Z" als erstes Zeichen automatisch gesetzt wird, benötigen wir nur noch die folgende Abgrenzung:
Im nächsten Schritt wählst du die Entitäten des Services, die du auch in diesem System verwenden willst. Da wir unseren Service nur mit einer Entität entwickelt haben, wird auch nur diese eine Entität vorgeschlagen:
Zum Abschluss erhältst du noch einmal eine Zusammenfassung aller Objekte, die generiert werden sollen, kannst die Objekte, sowie die verwendeten Namen noch einmal prüfen (in unserem Fall das Service Consumption Model, sowie pro Entität ein CDS View und eine Verhaltensdefinition):
Zum Abschluss findest du dich im generierten Service Consumption Model und bekommst einen Überblick über die generierten Objekte. In der linken Liste siehst du deine generierten Entitäten. Wenn du einen Eintrag wählst, werden auf der rechten Seite entsprechende Informationen nachgeladen, wie zum Beispiel der CDS View oder die Verhaltensdefinition. Im unteren Teil der rechten Seite werden Code-Snippets gezeigt, um auf die Daten zuzugreifen:
Lesen
Nachdem wir die Schnittstelle ans System angebunden haben, können wir den ersten Testaufruf über eine Klasse durchführen. Dazu können wir große Teile des Beispielcodes aus dem Fenster vom Service Consumption Model wiederverwenden und bauen damit die folgende Testmethode auf:
DATA:
lt_business_data TYPE TABLE OF zbs_rap_companynames.
TRY.
DATA(lo_client_proxy) = cl_web_odata_client_factory=>create_v2_remote_proxy(
EXPORTING
iv_service_definition_name = 'ZBS_DEMO_RAP_ONPREM_ODATA'
io_http_client = get_client( )
iv_relative_service_root = '/sap/opu/odata/sap/ZBS_API_COMPANY_NAMES_O2' ).
DATA(lo_request) = lo_client_proxy->create_resource_for_entity_set( 'COMPANYNAMES' )->create_request_for_read( ).
lo_request->set_top( 50 )->set_skip( 0 ).
DATA(lo_response) = lo_request->execute( ).
lo_response->get_business_data( IMPORTING et_business_data = lt_business_data ).
out->write( 'Data on-premise found:' ).
out->write( lt_business_data ).
CATCH cx_root INTO DATA(lo_error).
out->write( lo_error->get_text( ) ).
ENDTRY.
Zuerst wird der HTTP Client über die Destination erzeugt (Methode get_client) und daraus der HTTP Proxy für OData v2 generiert. Hierbei wird der Name des Service und der Teil der URL übergeben. Diese Informationen werden später für den Aufruf benötigt. Im Anschluss erzeugen wir eine Lese-Anfrage für unsere Entität und setzen einen TOP/SKIP Wert, um nur einen Teil der Daten zu lesen, wobei wir weniger als 50 Datensätze haben. Im Anschluss führen wir die Anfrage aus und lassen uns das Ergebnis zurückgeben. Für die Rückgabe wurde die abstrakte Entität automatisch mit angelegt, die wir für die Datenübernahme nutzen. Als Ergebnis erhalten wir die Daten aus On-Premise:
Die Erzeugung des Clients kann über ein Communication Arrangement erfolgen oder eine Destination in der BTP im Destination Service. In diesem Beispiel verwenden wir den Destination Service, der auf unser On-Premise System mit dem OData zeigt.
Das vollständige Beispiel der Testklasse aus dem ABAP Environment findest du hier:
CLASS zcl_bs_demo_read_odata 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>`.
METHODS:
get_client
RETURNING VALUE(ro_result) TYPE REF TO if_web_http_client
RAISING
cx_http_dest_provider_error
cx_web_http_client_error.
ENDCLASS.
CLASS zcl_bs_demo_read_odata IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA:
lt_business_data TYPE TABLE OF zbs_rap_companynames.
TRY.
DATA(lo_client_proxy) = cl_web_odata_client_factory=>create_v2_remote_proxy(
EXPORTING
iv_service_definition_name = 'ZBS_DEMO_RAP_ONPREM_ODATA'
io_http_client = get_client( )
iv_relative_service_root = '/sap/opu/odata/sap/ZBS_API_COMPANY_NAMES_O2' ).
DATA(lo_request) = lo_client_proxy->create_resource_for_entity_set( 'COMPANYNAMES' )->create_request_for_read( ).
lo_request->set_top( 50 )->set_skip( 0 ).
DATA(lo_response) = lo_request->execute( ).
lo_response->get_business_data( IMPORTING et_business_data = lt_business_data ).
out->write( 'Data on-premise found:' ).
out->write( lt_business_data ).
CATCH cx_root INTO DATA(lo_error).
out->write( lo_error->get_text( ) ).
ENDTRY.
ENDMETHOD.
METHOD get_client.
DATA(lo_destination) = cl_http_destination_provider=>create_by_cloud_destination(
i_name = c_destination
i_authn_mode = if_a4c_cp_service=>service_specific
).
ro_result = cl_web_http_client_manager=>create_by_http_destination( lo_destination ).
ENDMETHOD.
ENDCLASS.
Fazit
Dank der Verwendung von RAP auch On-Premise, können spielend leicht Schnittstellen für die BTP zur Verfügung gestellt werden. Wenn noch kein RAP zur Verfügung steht, dann kann dies auch klassisch über die SEGW gemacht werden.