BTP - OData Zugriff von On-Premise
In diesem Artikel werden wir etwas näher darauf eingehen, wie man einen OData Service auf dem ABAP Environment von On-Premise konsumieren kann.
Inhaltsverzeichnis
In bisherigen Szenarien sind wir vor allem davon ausgegangen, dass wir Daten aus dem On-Premise System oder anderen Systemen lesen. In diesem Artikel schauen wir uns die Konsumierung von Services aus dem On-Premise System an und wie uns das ABAP Environment Daten zur Verfügung stellen kann. Bereits in einem älteren Artikel hatten wir uns angeschaut, wie wir aus dem On-Premise System eine neue Entität anlegen können.
Einleitung
Das ABAP Environment dient vor allem zur Erweiterung von On-Premise Szenarien und zum Aufbau entkoppelter Anwendungen in der BTP. Daher verwenden wir verschiedene Arten von Kommunikation (OData, SOAP, RFC) um an Daten des On-Premise Systems zu kommen. Wollen wir nun Daten aus dem ABAP Environment lesen, die uns zur Verfügung gestellt werden, können wir dies ebenfalls tun, müssen aber einige Schritte gehen. Die Implementierung On-Premise ist allerdings nicht so einfach, da zum jetzigen Zeitpunkt das Consumption Model nicht zur Verfügung steht.
ABAP Environment
Bevor wir allerdings das ABAP Environment aufrufen, müssen wir noch einige Konfigurationsschritte auf der Umgebung durchlaufen.
Service Binding
Im ersten Schritt legen wir ein neues Service Bindung auf der Service Definition an, hierbei verwenden wir den Service unserer Simple RAP Schulung. Wir möchten die Partnerdatenbank On-Premise verwenden.
Dabei verwenden wir einen OData v2 Service als Web API Version, diesem geben wir einen entsprechenden Namen. Im unteren Teil wird noch einmal die Service Definition als Grundlage angeführt.
Hinweis: Im Anschluss nicht vergessen das Service Binding zu aktivieren und zu veröffentlichen, damit der Endpunkt aktiv zur Verfügung steht.
Communication Scenario
Im zweiten Schritt benötigen wir ein Communication Scenario, um den Service und die entsprechenden Berechtigungen zuordnen zu können. Das Szenario regelt später, welche Services von einem User und einer Verbindung genutzt werden können, wir müssen also aktiv entsprechende Einstellungen setzen. In den ADTs findest du über das Kontext-Menü "New -> Other Repository Object" den entsprechenden Eintrag.
Nachdem wir einen Namen vergeben haben und das Szenario angelegt wurde, wechseln wir auf den Reiter "Inbound", dort hinterlegen wir über den "Add" Button unseren Service. Der Name des Services weicht etwas zum Service Binding ab, über die Suche findest du ihn recht einfach.
Im nächsten Schritt wechseln wir auf den Reiter "Authorizations" und vergeben nun die Berechtigung zum Lesen der Daten auf der Tabelle. Dazu fügen wir die Berechtigung S_TABU_NAM hinzu und befüllen die Felder mit den passenden Ausprägungen für unsere Tabelle.
Hinweis: Zum Schluss unbedingt den Button "Publish Locally" betätigen, dann wird das Communication Scenario im Launchpad für die Konfiguration zur Verfügung gestellt.
Communication Arrangement
Im letzten Schritt müssen wir noch das Communication Arrangement einrichten, dazu benötigen wir Berechtigungen für die folgenden drei Apps, wobei wir nur "Communication Arrangements" aktiv starten. Die Berechtigungen findest du im Business Catalog "Communication Management" (SAP_CORE_BC_COM):
Öffnen wir nun also die App Communication Arrangements und legen über den "New" Button ein neues Arrangement an. Dabei suchen wir nach unserem zuvor angelegten Communication Scenario.
Da wir nun auch ein neues Communication System benötigen, können wir dieses direkt aus dem Detailbild über "New" anlegen.
Im Dialog vergeben wir nun einen neuen Namen, hier solltest du dich an eure Namenskonventionen halten oder definieren, wie solche Systeme heißen.
Bevor wir den User für den Zugriff anlegen, definieren wir das System als "Inbound only", hierzu findest du eine Checkbox im Communication System im Bereich "Technical Data -> General". Im unteren Abschnitt "Users for Inbound Communication" müssen wir nun über den "+" Button einen neuen User anlegen. Im Dialog dazu den "New" Button wählen.
Nun vergeben wir einen entsprechenden Namen für den technischen User, sowie ein geeignetes und starkes Passwort, welches wir dann für die Konfiguration On-Premise benötigen.
Zum Abschluss bestätigen und Speichern wir den User, sowie das System, bis wir wieder in unserem Communication Arrangement sind. Dort sollte nun der User und das System hinterlegt sein, welche wir zuvor angelegt hatten. Im unteren Teil siehst du die berechtigten Services im System, sowie den Pfad, um den Service aufzurufen.
Damit du weißt, dass die Konfiguration funktioniert hat und der User die passenden Berechtigungen hat, kannst du den Servicepfad kopieren und im Browser öffnen. Es sollte nun eine Anmeldung erforderlich sein und nach Eingabe des Users und Passworts, sollten wir eine Übersicht der Entitäten bekommen.
On-Premise
Nach der Einrichtung des ABAP Environments muss nun das On-Premise System konfiguriert werden, sodass wir den neuen Endpunkt aufrufen und verwenden können.
Verbindung
Im ersten Schritt müssen eine Verbindung zum ABAP Environment herstellen, das geht am einfachsten über die Anlage einer Verbindung in der Transaktion SM59. Dazu richten wir eine neue Verbindung vom Typ "G" ein, als Host definieren wir das System "<ID>.abap.eu10.hana.ondemand.com" und den Port 443, da wir per HTTPS kommunizieren wollen.
Im Reiter "Security & Logon" hinterlegen wir den technischen User und das Passwort, die Anmeldung erfolgt hier per "Basic Authentication". Im unteren Teil noch SSL aktivieren und die neue Verbindung sichern. Über den Verbindungstest sollten wir nun einen Status Code von 200 erhalten, sodass die Verbindung eingerichtet ist.
Ausführung
Über CL_HTTP_CLIENT und unsere neue Verbindung erzeugen wir einen Client um auf den Endpunkt zugreifen zu können. Den Endpunkt steuern wir über das zusätzliche Header-Feld an, setzen den entsprechenden Pfad zum Service, die Entität und möchten als Ergebnis gern ein JSON haben.
cl_http_client=>create_by_destination( EXPORTING destination = c_destination
IMPORTING client = mo_http_client ).
mo_http_client->request->set_header_field(
name = '~request_uri'
value = '/sap/opu/odata/sap/ZBS_API_SIMPLE_PARTNER_O2/Partner?$format=json' ).
Schauen wir uns den Aufruf einmal im Browser an, sehen wir die Struktur des JSON. Dafür müssen wir nun ein entsprechendes Mapping einrichten, um die Daten in ein ABAP Format zu bekommen.
Dazu richten wir uns entsprechende Typen ein, die die JSON Struktur wiederspiegeln. Hierbei kannst du Felder und Informationen weglassen, die du später für die Verarbeitung nicht benötigst.
TYPES: BEGIN OF ts_data,
PartnerNumber TYPE char10,
partnername TYPE text60,
street TYPE char80,
city TYPE text60,
country TYPE land1,
paymentcurrency TYPE waers,
END OF ts_data.
TYPES tt_data TYPE STANDARD TABLE OF ts_data WITH EMPTY KEY.
TYPES: BEGIN OF ts_result,
results TYPE tt_data,
END OF ts_result.
TYPES: BEGIN OF ts_root,
d TYPE ts_result,
END OF ts_root.
Nachdem das Mapping über /UI2/CL_JSON=>DESERIALIZE durchgeführt wurde, sehen unsere Daten im Debugger wie folgt aus:
Vollständiges Beispiel
Hier noch einmal das vollständige Beispiel der Klasse, die den Service aufruft und die Daten von JSON in eine interne Tabelle umwandelt. Auf ein entsprechendes Fehlerhandling haben wir in diesem Beispiel verzichtet, gehört aber natürlich in den produktiven Quellcode.
CLASS zcl_bs_demo_simple_access DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
CONSTANTS c_destination TYPE rfcdest VALUE 'TEST_SIMPLE'.
PRIVATE SECTION.
TYPES: BEGIN OF ts_data,
PartnerNumber TYPE char10,
partnername TYPE text60,
street TYPE char80,
city TYPE text60,
country TYPE land1,
paymentcurrency TYPE waers,
END OF ts_data.
TYPES tt_data TYPE STANDARD TABLE OF ts_data WITH EMPTY KEY.
TYPES: BEGIN OF ts_result,
results TYPE tt_data,
END OF ts_result.
TYPES: BEGIN OF ts_root,
d TYPE ts_result,
END OF ts_root.
DATA mo_http_client TYPE REF TO if_http_client.
METHODS call_service_and_get_json
RETURNING VALUE(rd_result) TYPE string.
METHODS convert_json_to_data
IMPORTING id_json TYPE string
RETURNING VALUE(rs_result) TYPE ts_root.
ENDCLASS.
CLASS zcl_bs_demo_simple_access IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(ld_json) = call_service_and_get_json( ).
DATA(lt_data) = convert_json_to_data( ld_json ).
out->write( lt_data ).
ENDMETHOD.
METHOD call_service_and_get_json.
cl_http_client=>create_by_destination( EXPORTING destination = c_destination
IMPORTING client = mo_http_client ).
mo_http_client->request->set_header_field(
name = '~request_uri'
value = '/sap/opu/odata/sap/ZBS_API_SIMPLE_PARTNER_O2/Partner?$format=json' ).
mo_http_client->send( EXCEPTIONS http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4
OTHERS = 5 ).
IF sy-subrc <> 0.
ENDIF.
mo_http_client->receive( EXCEPTIONS http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
OTHERS = 4 ).
IF sy-subrc <> 0.
ENDIF.
mo_http_client->response->get_status( IMPORTING code = DATA(ld_code)
reason = DATA(ld_reason) ).
rd_result = mo_http_client->response->get_cdata( ).
ENDMETHOD.
METHOD convert_json_to_data.
/ui2/cl_json=>deserialize( EXPORTING json = id_json
CHANGING data = rs_result ).
ENDMETHOD.
ENDCLASS.
Fazit
Damit haben wir Daten aus einem ABAP Environment auch einem On-Premise System zur Verfügung gestellt und können damit weiterarbeiten. Die Anbindung erfordert einiges an Schritten, bis der eigentliche Zugriff funktioniert, sollte aber mit Hilfe des Artikels kein Problem mehr sein.