Adobe Forms API Integration BTP

Willkommen zu einem weiteren Blog-Beitrag über SAP Cloud Architektur. In dieser Ausgabe unseres technischen Blogs befassen wir uns mit einer Herausforderung, auf die wir in der Anfangsphase unserer internen App-Entwicklung in diesem Jahr gestoßen sind. Unsere Aufgabe war es nämlich, auf der SAP FIORI Elements Framework basierenden List Report Applikation ein PDF Dokument zu erzeugen. Die zugrundeliegende Anforderung war, ein Mitarbeiterprofil als PDF zu exportieren. 

 

Leider stellten wir auf Anfrage fest, dass die SAP standardmäßig keine Annotation (zum Anfragezeitpunkt) oder Funktion out-of-the-box anbietet. Darüber hinaus würde auch eine bereits vorhandene Standardfunktion nicht die Anforderung an ein firmengerechtes PDF-Formular erfüllen, wenn lediglich ein PDF-Ausdruck aus der Anwendung ohne individualisierte Anpassungen generiert werden würde. Aus diesen Gründen musste eine Lösung her, die mit diesen Anforderungen umgehen konnte – die Aufmerksamkeit war daher auf die SAP Adobe Forms Integration gerichtet.

 

In diesem Blog möchte ich nun aufführen, wie die PDF-Dokumenterzeugung innerhalb einer CAP basierten Anwendung möglich ist. Die Vorgehensweise ist aber auch für SAP UI5 Freestyle Applikationen in ähnlicher Form anwendbar und geeignet. In beiden Fällen kommt die Adobe Forms API zum Einsatz, die auf der der BTP als Service „SAP Forms“ bereitgestellt und aus der Applikation über die Adobe REST API mittels http-Aufruf konsumiert werden kann. Der Blog richtet sich vor allem an Entwickler und technische Product Owner, die sich für die Integration mit Adobe interessieren. Es werden daher keine lizenztechnischen Fragestellungen beantwortet. Als Beispiel soll dabei ein einfaches Formular im Mitarbeiterprofil im PDF-Format ausgegeben werden.

 

In der Cloud Foundry-Umgebung kann die REST-API des SAP Forms Service genutzt werden, um PDFs zu rendern und um PDF basierte Formularvorlagen in der Cloud zu speichern, oder den SAP Forms Service verbinden, um Dokumente zu rendern, die von der Cloud Applikation angefragt werden.

 

Die Voraussetzung dafür ist allerdings, dass ein Unterkonto auf SAP BTP innerhalb der Cloud Foundry-Umgebung verfügbar ist und dass das Unterkonto die Berechtigung für den Service „Forms Service by Adobe“ besitzt. Auch die Region des Subaccounts spielt eine wichtige Rolle, da dies die Verfügbarkeit beeinträchtigt. So war in unserem Setup der Service Adobe Forms in der deutschen und amerikanischen Region vorhanden, aber z.B. nicht in der kanadischen.

Die wichtigsten Schritte sind dabei wie folgt:

1. Instanz für ADS-Abonnement erstellen

Als erstes wird ein Abonnement für „Forms Service by Adobe“ im Firmen-Subaccount von BTP, innerhalb des CF-Environments angelegt. Als Plan wird „Standard“ selektiert und der BTP space („dev“) ausgewählt.

Sobald die Serviceinstanz angelegt worden ist, können die Details mit weiteren Optionen eingeblendet werden.

2. Instanz-Service für Adobe API

Im selben Subaccount wird im zweiten Schritt eine Instanz für Forms Service by Adobe API (!) angelegt. Hierzu bitte unbedingt den Unterschied im Namen achten.

3. Generierung Service Key

Im nächsten Schritt wird ein Service Key für die genannte Instanz generiert.

Über die angebotene „View“-Funktion innerhalb der Detailsicht kann der Inhalt des Servicekeys eingesehen werden.

Aus der Ansicht des Service Keys wird nun die Adobe Forms URL herauskopiert und um den Endpunkt „swagger-ui/index.html“ ergänzt:

Über die nun angepasste URL gelangt man nun auf die Swagger UI Oberfläche von Adobe Forms:

https://adsrestapi-formsprocessing.cfapps.us10.hana.ondemand.com/swagger-ui/index.html

Hintergrund: Der SAP Forms Service by Adobe REST API bietet eine Teilmenge der bekannten Funktionen von ABAP PDF Object. Sie werden über verschiedene URIs (=Uniform Resource Identifiers) angesprochen, wobei jeder URI den Austausch von Daten und Dokumenten im JSON-Format unterstützt. Die Anwendung ruft den SAP Forms Service by Adobe REST API über das sichere HTTPS-Protokoll auf.

Über die aufgerufene Swagger UI ist es möglich, auf die Dokumentation des SAP Forms Service REST API und des Template Store zuzugreifen. Die Dokumentation beschreibt alle relevanten Endpunkte sowie die Eingabe- und Ausgabeparameter. Hierbei ist die Dokumentation in sechs verschiedene Bereiche unterteilt:

  1. ADS – Get-Anfragen
  2. ADS – Set-Anforderungen
  3. ADS – Render-Anfragen – PDF rendern
  4. Speichern – Formulare
  5. Speichern – Schema
  6. Speichern – Schablonen

4. Berechtigungen/Rollenzuweisungen:

Nachdem diese Schritte getätigt worden sind, ist es erforderlich, die zu berechtigenden Adobe Forms Rollen dem BTP-User des Anwenders oder des Entwicklers zuzuweisen.

Dazu navigiert man auf die „Role Collections“ und filtert die Liste auf „Adobe“. Daraufhin werden die benötigten Rollen angeboten:

Diese Rollen können durch die Auswahl der Zeile einem entsprechenden User zugewiesen werden, indem hier die zugehörige E-Mail-Adresse eingetragen wird.

5. Adobe Forms Store

Nun kann die Vorlagendatei in den Forms Service Store von Adobe hochgeladen werden:

Dazu wird die Adobe Form Service Adresse kopiert, die man wie folgt zusammenbaut und in die Browser Zeile einträgt:

Die Form Template store URL ist : a. url + /adsrestapi/ui.html (abgeänderte URL für Blogeintrag)

https://development-XXXXXXX-ads.formsprocessing.cfapps.us10.hana.ondemand.com/adsrestapi/ui.html

Über „Create Form“ wird hier ein neuer Template-Eintrag für das noch zu entwickelnde Formular angelegt.

Damit haben wir die Voraussetzung geschaffen, einen Container für ein lokal noch zu entwickelndes Formular bereitzustellen. Ein Adobe PDF Formular kann z.B. mittels Adobe Livecycle Designer gebaut werden oder man lädt ein fertiges Test-Exemplar von SAP oder einem Partnerunternehmen runter. Dieses kann dann für firmenspezifische Bedürfnisse angepasst und an dieser Stelle hochgeladen werden. Das XDP-Element kann über Adobe LiveCycle Designer bearbeitet werden:

Eine Versionsverwaltung ist mit diesem Tool ebenfalls inkludiert.

Schließlich kann das PDF-Templates unter Angabe der Sprache, Lokation und Namen auch im Template Store hochgeladen werden:

Die Formular Details sind unten abgebildet – u.a. ist gut sichtbar die Versionierung. Neue Versionen des PDF-Formulars können hier als Update zum bestehenden Formular hochgeladen werden – auch Optionen wie die Duplizierungen, Textverwaltung und das Löschen werden hier angeboten.

Auf diese Weise wurde nun das auf XDP basierende Element im ADS erzeugt und kann über die Adobe Forms API über die Applikation angesprochen werden.

Die Form Template kann über Postman vorab getestet werden, um die API zu erlernen:

Ein sehr guter Blogeintrag von einem SAP Adobe Experten Jacky Liu ist unter dem folgenden Link zugänglich: https://blogs.sap.com/2022/01/24/configure-the-sap-btp-cloud-foundry-environment-subaccount-with-sap-forms-service-by-adobe/

Soll die API direkt aus der Applikation aufgerufen werden, sind die folgenden Parameter wie folgt zu befüllen:

Method : Post

URL: From 3  URI + Swagger render api path

Authorization Type : OAuth 2.0

Authorization token url, client key client secret are from 3 instance key.

parameters:

templateSource:  storageName

TraceLevel, 2

6. CAP Applikation - Implementierung

In unserer SAP CAP Applikation benötigen wir einen Event, der die Daten aus dem Kontext der Applikation liest und an die Adobe API übergibt:

Dazu haben wir zwei Möglichkeiten:

  1. Anlage einer Destination zur Kommunikation mit der API
  2. Direkter Aufruf der Adobe API URL aus der Applikation heraus

Hierbei soll hervorgehoben werden, dass die Best-Practice Methode die Nutzung der Destination innerhalb der Applikation ist, anstatt die API URL direkt über einen vorherigen Token Abruf zwecks Authentifizierung aufzurufen.

Die Anlage einer Destination zur API URL auf der BTP würde wie folgt aussehen:

URL: uri in service key

Client ID: aus aa clientid in service key

Client Secret: aus uaa clientsecret im Service key

Token Service URL: service key uaa url + ‘/oauth/token’

Token Service User: aus uaa clientsecret im Service key

Token Service Password: aus uaa clientsecret in service key

Wichtig ist, dass die SAP CAP Anwendung mit der Adobe Form Instanz zunächst gebunden werden muss, bevor ein Deployment erfolgt oder die Adobe Forms API überhaupt programmatisch angesprochen werden kann. Für den lokalen Aufruf muss die Datei „.cdsrc-private.json“ um das folgende Binding angepasst werden:

Dies geschieht allerdings nicht manuell, sondern über das BAS-Terminal:

Durch die Anweisung „cds bind -2 adobeapi:adobeapikey“ wird das Binding mit der Adobe Form Instanz automatisch hergestellt.

Weiter muss zwecks BTP-CF Deployment innerhalb der mta.yaml file die Adobe Form Instanz als Ressource wie folgt angegeben und mit der Anwendung verknüpft werden:

Darüber hinaus ist es zwingend erforderlich, innerhalb der „xs-app.json“ Datei, eine neue Route für die Adobe Forms API anzugeben:

Über die xs-app.json file wird definiert, dass die Anfrage an Adobe als Backend-Dienst (als sog. Route) weitergeleitet wird und wie diese Anfrage darüber authentifiziert werden muss.

Innerhalb der CAP-Anwendung muss als erstes eine nicht-persistente, CDS basierten Entität implementiert werden. Dazu wird diese innerhalb der CDS-Datenmodelldefinition (z.B. schema.cds) mit den abgebildeten Annotationszusätzen definiert:

Diese Entität ist erforderlich, um die Forms Service API innerhalb des Service-Handlers aufzurufen. Auf diese Weise kann der aktuelle Kontext des OData-Aufrufs für das angezeigte Dokument auf der Object Page verwendet und die relevanten Informationen an die Forms Service API übergeben werden, damit die PDF mit den aktuellen Dokumentdaten erzeugt wird. Nach der Entitätsdefinition muss diese als Service-Entität bereitgestellt werden. In unserem Fall haben wir dazu die service.cds Datei und fügen die folgende Zeile hinzu, um einen auf diese Entität basierenden OData-Dienst zu generieren:

Code-Erklärung:

Im Nachfolgenden wird innerhalb des Servicehandlers ein „READ“- Service Handler für die Service-Entität „PDFDoc“ implementiert. In CAP ist dies besonders vorteilhaft, dass Informationen aus anderen Entitäten leicht abgefragt werden können. Dabei sind keine Datenbankselektionen erforderlich, sondern der Zugriff geschieht auf Serviceebene. So kann aus unserer CV_Header Entität die explizite Instanz aus dem Kontext, in dem wir uns befinden, asynchron durch die CAP spezifische CQL Sprache (= Query Languge) aufgerufen (await tx.run(SELECT XX)) und für das Formular als Datengrundlage verwendet werden:

Der Dokumentschlüssel sollte von der UI5-Erweiterung gesendet und bei einer Abfrage der Entität verwendet werden. Der XML-String wird mit den von diesem Select abgerufenen Daten erstellt.

Aufgrund des im vorausgegangenen Schritt vorgenommenen Service Binding erhalten wir die notwendigen Parameter für den Aufruf des SAP Forms Service. Neben den unten aufgelisteten statischen Parametern wird der XML-string zuerst über die Buffer-Funktion in das base64 Format enkodiert und dann in die Variable „bodyE“ geschrieben sowie als JSON Attribut definiert:

Exkurs: Die Base64-Kodierung wird verwendet, um binäre Daten, z. B. eine PDF-Datei, in ein ASCII-String-Format zu kodieren, das mit Systemen kompatibel ist, die nur Text verarbeiten können. Schließlich wird der JSON-String mit den PDF-Optionen an die Adobe API wie folgt übergeben:

Mit dem AXIOS Call wird der Formulardienst angesprochen und der Inhalt der generierten PDF-Datei abgerufen. Hierbei wird die zuvor auf BTP angelegte Destination „adobeapi“ verwendet. Somit ist eine Authentifizierungsanfrage innerhalb des Codings nicht mehr erforderlich, da die Destination das regelt. Die AXIOS-Methode erleichtert die Verarbeitung des bereitgestellten Artworts. Das Ergebnis (base64Pdf) wird dann als Antwort des ursprünglichen Aufrufs an die als nächstes zu implementierende SAPUI5-Erweiterung weitergegeben:

7. SAPUI5 Implementierung – Controller Extension

Dazu wird eine benutzerdefinierte Aktion in der manifest.json-Datei der Anwendung erstellt: (..\app\<sapui5app>\webapp\manifest.json), unter sap.ui5 → Routing → Targets → <Object Page Target Name> → Options → Settings → Content→ Header → Actions. In unserer Applikation ist der Header als „CV_HeaderObjectPage“ bezeichnet, was die Detailseite der Applikation bezeichnet.

Unter „ ..\app\<sapui5app>\webapp„ wird der Ordner ext (steht für Extenssions) erstellt – für den benutzerdefinierten Controller „CustomPDFActions.js“. Die App Ordnerstruktur sieht daraufhin wie folgt aus:

Auf diese Weise sollte auf der Detailseite im Header der Instanz nun ein neuer Button sichtbar sein („Print Profile“).

Dieser Button triggert unsere Implementierung und ruft die Adobe Forms API auf.

Code-Erklärung:

Ein jQuery GET wird mit dem OData-Service durchgeführt, der an die Ansicht gebunden ist. Der Aufruf erfolgt an das Entity-Set „PDFdoc“, das im vorherigen Schritt deklariert wurde:

8. Ergebnis

Die GET-Abfrage auf die Entität gibt also das base64-PDF zurück, das in ein Byte-Array dekodiert und an sap.m.PDFViewer übergeben werden muss. Danach kann das MTA-Projekt neu erzeugt und in CF deployed werden. Als Ergebnis wurde das PDF-Dokument erzeugt, das mit Daten aus einer CAP Fiori Element App befüllt wurde:

Natürlich handelt es sich hier zunächst um ein rudimentäres, einfaches Formular als Ergebnis. Aber es ist ein wichtiger Schritt, sowohl die generelle Herangehensweise an den Konsum von BTP-Services aus einer Applikation, das Binding, zu verstehen als auch die Grundlage für die firmenspezifische Erweiterung des Formulars zu schaffen.

 

Hilfsressourcen:

Für diesen Blogeintrag und die Implementierung haben mir insbesondere die folgenden SAP Blogs geholfen:

https://blogs.sap.com/2023/01/30/using-custom-actions-to-display-pdf-from-sap-btp-forms-service-into-a-cap-sapui5-application/

https://blogs.sap.com/2022/11/23/render-and-view-pdf-in-sap-ui5-with-forms-service-by-adobe-in-btp/

https://blogs.sap.com/2019/10/16/consume-sap-forms-by-adobe-from-sap-ui5-applications/

Daher empfehle ich allen Lesen, diese ergänzend zu meinem Blogeintrag ebenfalls anzuschauen.

Ich bin studierter Wirtschaftsinformatiker (M.Sc.) und arbeite bereits seit über 10 Jahren im Umfeld der SAP Cloud. Beginnend mit Business ByDesign liegt mein Schwerpunkt inzwischen auf der Einführung und dem Betrieb von SAP C/4 Sales Cloud und der Implementierung von Anwendungen auf der SAP BTP. Eine breit gefächerte, technische sowie fachliche Expertise im SAP-Umfeld ermöglicht es mir, Sie zielgerichtet bei der Analyse, Implementierung und Optimierung von IT-Architekturen zu beraten.

rufat Gadirov

Telefon: +49 (0) 151 7420 8356

E-Mail: rufat.gadirov@jfs-digital.com