Skip to Content
Technical Articles
Author's profile photo Pascal Bremer

SAP Forms service by Adobe in SAP BTP, ABAP environment

I’m sure that by now you have already started your Cloud journey in ABAP. Maybe you’ve just published a new business scenario, extended a CDS view, or debugged in your classes.

In this blog, I want to present a business case almost every customer needs to implement in some way: Printing!

This blog post might seem similar to this one: https://blogs.sap.com/2020/04/03/generate-pdfs-in-sap-cloud-platform-abap-environment/. In this post however, we are exclusively using services in Cloud Foundry, offer a full product scenario, a setup guide and example objects.

This guide is designed to be used along with the objects published in the SAP-samples Github repository:https://github.com/SAP-samples/forms-service-by-adobe-samples. This will create a working scenario out of the box and you only need to perform the initial setup. You can import the demo objects from the Github repository via ABAPgit, activate all objects, and execute zcl_dsag_fill_data to write some test data to your database.

The form templates will be stored directly on the SAP Business Technology Platform. So they could theoretically be accessed by multiple systems. For this guide a demo template is provided and can be accessed here: Demo Template. After the initial setup, you can publish a demo invoice to your print queue (see Running the example).

  1. Learning by example
  2. Infrastructure
  3. Services and what they are for
    1. SAP Destination service
    2. ABAP environment
    3. SAP Forms Service by Adobe (+API)
  4. Setup
    1. SAP Forms Service by Adobe
    2. SAP Destination service
    3. ABAP environment
      1. Print Queue
      2. Connect to SAP Destination service
      3. SAP Forms Service by Adobe
  5. Running the example
    1. Upload the demo template
    2. Run the example program
  6. Understanding and extending the demo project
    1. Data service
    2. ABAP Template Store Client
      1. Initialize the client connection
      2. Upload a data schema to a form in the template store
      3. Download an existing template in a form on the template store
    3. Form Layout Development

Learning by example

Imagine that your product management team starts a new project to realize a new purchase order solution in SAP Business Technology Platform. In this blog, we want to explore how such a requirement could be realized using SAP BTP services and the SAP BTP, ABAP environment. Our goal will be to create the following output:

Our%20desired%20output

Our desired output

Infrastructure

Before we start implementing this example, we first need to get a rough overview of our Cloud Foundry space.

Tools:

Here is a short list of services that are needed:

Services and what they are used for

Destination Service

The SAP Destination service is used to connect services and applications to third-party services. Connection information including credentials can be maintained centrally using this service.

The SAP Destination service will be used by the SAP BTP, ABAP environment to connect to the Template Store hosted by the Forms Service by Adobe API.

ABAP environment

The “brain” of our operation. We will store and define our business data and data services in ABAP. The ABAP environment will also connect to all the external services and provide the rendered print files via the integrated print queue.

SAP Forms Service by Adobe (+API)

SAP Forms service by Adobe is the cloud-based form rendering solution of SAP. The technology is based on the Adobe Document Services (ADS).

With the Forms service by Adobe API we offer a central Adobe form template storage solution (template store).

Setup

Before we can start programming our example in ABAP and Adobe LiveCycle Designer 11.0 for SAP solutions we first need to set up all the dependent services. The following section assumes you are familiar with the SAP BTP, Cloud Foundry environment. Especially how to subscribe and consume services via the cockpit. If you are new to this product I recommend reading the dedicated help page before continuing.

SAP Forms Service by Adobe

  1. Create a new subscription for Forms Service by Adobe (plan: default)
  2. Create a new role collection and assign the following roles to it:
    1. ADSAdmin for accessing Forms Service by Adobe Config UI (used for maintaining fonts, xdc, xci, etc.)
    2. TemplateStoreAdmin for accessing the template store UI
  3. Create a new instance and service key for the service: Forms Service by Adobe (plan: standard)
  4. Create a new instance and service key for the service: Forms Service by Adobe API (plan: standard)

You might be wondering why we need subscription and service instances. The initial subscription is necessary to enable the service config UIs (ADS Config UI / Template Store Admin UI) and to set up your tenant data. Without it, the services will not function as intended. To access the UIs, you need to authorize the users via a custom role collection.

Service instances are used to give external systems access to the service. External systems don’t have a user maintained in Cloud Foundry, so we need specific credentials to authorize these systems.

The service instance for SAP Forms service will be used by the ABAP environment to render a print file (e.g. PDF), and the service instance to Forms Service by Adobe API enables us to connect to the template store.

Destination

To allow the ABAP environment to access the template store, we need to pass on the information of the service key (for the Forms Service by Adobe API). To avoid hardcoding this connection information we will create a specific destination to the template store using the Cloud Foundry destination service.

Once we have connected the destination service to the ABAP environment, we can reuse all the maintained destinations.

To create a destination to the template store you need to:

  1. Create a new instance and service key for the service: Destination
  2. Maintain a new destination pointing to the service instance of Forms Service by Adobe API using the corresponding service key

ABAP environment

Print Queue

To provide our physical printer with the print files stored in the print queue we need to use a proxy service that retrieves the files and sends them to the corresponding printer. To enable this service, we need to maintain a communication user, a communication arrangement and a new specific print queue.

Follow the setup guide here: https://blogs.sap.com/2017/08/07/cloud-print-manager-installation-and-configuration/. Make sure you note down the name of your print queue. This guide assumes the name of the print queue to be PRINT_QUEUE, if not, you need to adjust the final script accordingly.

Connect to CF Destination service

Create a new communication arrangement (scenario: SAP_COM_0276) with the service key of the destination service instance.

SAP Forms Service by Adobe

  1. Download the service key for the instance of Forms Service by Adobe (from SAP BTP Cockpit)
  2. Open the Communication Systems app.
  3. Create a new communication system (to connect to Forms Service by Adobe service instance):
    1. System ID: <any name>
    2. System Name: <any name>
    3. Host Name: <uri in service key>
    4. Auth. Endpoint: <uaa.url in service key>/oauth/authorize
    5. Token Endpoint: <uaa.url in service key>/oauth/token
    6. Create new users for outbound communication:
        • Authentication Method: OAuth 2.0
        • OAuth 2.0 Client ID: <uaa.clientid in service key>
        • Client Secret: <uaa.clientsecret in service key>
  4. Save the system

  1. Open the Communication Arrangement app.
  2. Create a new communication arrangement (scenario: SAP_COM_0503):
    • Communication System: <system that connects to the Forms Service by Adobe service instance>
    • OAuth 2.0 Client ID: <Should be automatically selected>
    • Path: </AdobeDocumentServicesSec/Config>

Expected%20result%20for%20check%20connection%20%28Ping%20Error%29

Expected result for check connection (Ping Error)

Running the example

If you’re just interested in a quick proof-of-concept project or if you want to start extending a basic example, a sample project is provided.

Upload the demo template

  1. Access the Template Store Admin UI
  2. Create a new form
  3. Upload the demo template (https://github.com/SAP-samples/forms-service-by-adobe-samples/blob/main/abap/Form.xdp)

Run the example program

I created a short runnable class that renders a PDF using the business data and template from the template store. The generated print files will then be sent to the print queue. If you plan to run this, make sure the hard-coded values are adjusted to your environment.

Make sure you have generated the test data beforehand by running class zcl_dsag_fill_data.

CLASS zcl_dsag_execute_fdp DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES: if_oo_adt_classrun.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_dsag_execute_fdp IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    try.
      "Initialize Template Store Client
      data(lo_store) = new ZCL_FP_TMPL_STORE_CLIENT(
        "name of the destination (in destination service instance) pointing to Forms Service by Adobe API service instance
        iv_name = 'restapi'
        "name of communication arrangement with scenario SAP_COM_0276
        iv_service_instance_name = 'SAP_COM_0276'
      ).
      out->write( 'Template Store Client initialized' ).
      "Initialize class with service definition
      data(lo_fdp_util) = cl_fp_fdp_services=>get_instance( 'ZDSAG_BILLING_SRV_DEF' ).
      out->write( 'Dataservice initialized' ).
      
      "Get initial select keys for service
      data(lt_keys)     = lo_fdp_util->get_keys( ).
      lt_keys[ name = 'ID' ]-value = '1'.
      data(lv_xml) = lo_fdp_util->read_to_xml( lt_keys ).
      out->write( 'Service data retrieved' ).
      
      data(ls_template) = lo_store->get_template_by_name(
        iv_get_binary     = abap_true 
        iv_form_name      = 'DSAG_DEMO' "<= form object in template store
        iv_template_name  = 'TEMPLATE' "<= template (in form object) that should be used
      ).

      out->write( 'Form Template retrieved' ).

      cl_fp_ads_util=>render_4_pq(
        EXPORTING
          iv_locale       = 'en_US' 
          iv_pq_name      = 'PRINT_QUEUE' "<= Name of the print queue where result should be stored
          iv_xml_data     = lv_xml
          iv_xdp_layout   = ls_template-xdp_template
          is_options      = value #(
            trace_level = 4 "Use 0 in production environment
          )
        IMPORTING
          ev_trace_string = data(lv_trace)
          ev_pdl          = data(lv_pdf)
      ).

      out->write( 'Output was generated' ).

      cl_print_queue_utils=>create_queue_item_by_data(
          "Name of the print queue where result should be stored
          iv_qname = 'PRINT_QUEUE'
          iv_print_data = lv_pdf
          iv_name_of_main_doc = 'DSAG DEMO Output'
      ).

      out->write( 'Output was sent to print queue' ).
    catch cx_fp_fdp_error zcx_fp_tmpl_store_error cx_fp_ads_util.
      out->write( 'Exception occurred.' ).
    endtry.
    out->write( 'Finished processing.' ).
  ENDMETHOD.
ENDCLASS.

If everything worked correctly you should receive a PDF similar to the one shown at the beginning. You can now take a deeper look at the CDS views, classes, and form layout provided.

Understanding and extending the demo project

The example output works. Now you can proceed by extending the objects in your system to fit your use cases.

For form development in general, I recommend the following steps:

  1. Design your data service.
  2. Create your form template based on your data service.
  3. Design your output process in ABAP.

Data service

In our example, the root node will be ZI_DSAG_BILL_ORDER. The root node is the starting node of our resulting data tree. This node is usually determined by checking which nodes have no associations pointing to them.

Given the data service above, the output of the data service might look like this:

To generate data from our CDS views we need to expose them via a service definition (a service binding is not needed for our use case).

@EndUserText.label: 'Service Destination for billing example'
define service ZDSAG_BILLING_SRV_DEF {
  expose ZI_DSAG_BILL_ITEM;
  expose ZI_DSAG_BILL_ORDER;
  expose ZI_DSAG_PRODUCT;
  expose ZI_DSAG_RECEIVER;
}

The xml data can now be generated using the following example:

"Initiate data service from definition
data(lo_fdp_util) = cl_fp_fdp_services=>get_instance( 'ZDSAG_BILLING_SRV_DEF' ).

"Retrieve the key fields of the root node
data(lt_keys)  = lo_fdp_util->get_keys( ).

"Fill out key fields (depends on your actual data)
lt_keys[ name = 'ID' ]-value = '1'.

"Execute the data service and retrieve the data tree
data(lv_xml) = lo_fdp_util->read_to_xml( lt_keys ).

"Generate data schema from your service
data(lv_schema) = lo_fdp_util->get_xsd(  )

ABAP Template Store Client

To upload or download a form template design to the ABAP environment I implemented a template store client as Z-coding (available in the GitHub repository). Here are some essential examples showing how this client is used in ABAP:

Initialize the client connection

"Initialize Template Store Client
data(lo_store) = new ZCL_FP_TMPL_STORE_CLIENT(
  "destination name connecting to the template store in cf destination service
  iv_name = 'restapi'

  "name of the comm. arrangement connecting the cf destination service
  iv_service_instance_name = 'SAP_COM_0276'
).

Upload a data schema to a form in the template store

try.
  "Get data schema for form object
  lo_store->get_schema_by_name( iv_form_name = 'DSAG_DEMO' ).

catch zcx_fp_tmpl_store_error into data(lo_tmpl_error).
  "Error occurred
  "Check if error occurred because no schema was found
  if lo_tmpl_error->mv_http_status_code = 404.
    "Upload a new schema to form object
    lo_store->set_schema(
      iv_form_name = 'DSAG_DEMO'
      "Generate schema from the data service util
      is_data = value #( note = '' schema_name = 'schema' xsd_schema = lo_fdp_util->get_xsd(  )  )
    ).
  else.
    "Get error: lo_tmpl_error->get_longtext(  ).
  endif.
endtry.

Download an existing template in a form on the template store

data(ls_template) = lo_store->get_template_by_name(
  "Should the xdp template be retrieved or only metadata
  iv_get_binary     = abap_true
  "Name of the form object in the template store
  iv_form_name      = 'DSAG_DEMO'
  "Name of the template in the template store
  iv_template_name  = 'TEMPLATE'
).

"To access the template data use:
ls_template-xdp_template

Form Layout Development

It’s often very helpful to have the data schema of the business service available before you start to to develop your form template. It’s advisable to first develop your data service and then execute a classrun to upload the schema to a form object in the template store (see the example above: Upload a data schema to a form in the template store). You can then download the xsd schema file from the template store.

Alternatively, the generated xsd file is also available on Github.

To import the schema into the Adobe LiveCycle Designer 11.0 for SAP solutions:

  1. Open the application and go to the tab: Data View.
  2. Right-click an empty area and select: New Data Connection…

  3. Create a new connection from a schema:
  4. Now the Adobe LiveCycle Designer 11.0 for SAP solutions will offer you syntax highlighting for the data binding of the fields.

I hope this guide gave you a good overview of what is possible in SAP BTP using cloud-native services.

Happy printing and best regards,
Pascal Bremer

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Gurpreet Jaspal
      Gurpreet Jaspal

      Thanks for the detailed explanation. Much appreciated!!