Skip to Content
Technical Articles
Author's profile photo Sindy Zhan

Create a Simple Cloud Foundry App Using SAP Cloud SDK Tutorial Implementation Notes

This blog post is following up on the SAP Cloud SDK for Java (version 4.0.0 just released) introduction tutorial on SAP Developers Community, Create a Simple Cloud Foundry App Using SAP Cloud SDK , which provides a hands-on to create a very simple servlet retrieving Business Partner information from an OData service system, and then deploy the application onto Business Technology Platform, Cloud Foundry environment. The purpose is to provide a procedure-concentrated guide and expand the details on each step, especially the steps to connect to the OData service, as a compliment to the original tutorial.

Although there are multiple alternatives to implement the original tutorial, here in this blog post we will only show the path that I took. Specifications:

  • backend OData system: SAP S/4HANA Cloud
  • deploy environment: SAP BTP, Cloud Foundry
  • local machine: macOS (Terminal)
  • IDE: Eclipse (with maven plugin)

References

Original tutorial (in java) https://developers.sap.com/group.s4sdk-cloud-foundry.html

SAP Cloud SDK document  https://sap.github.io/cloud-sdk/docs/java/getting-started

M2Eclipse http://www.eclipse.org/m2e/

Environment Setup

➡️ Install JAVA 8

First you need to check if java is installed.

java --version

I got the result:

openjdk 18 2022-03-22
OpenJDK Runtime Environment SapMachine (build 18+36-sapmachine)
OpenJDK 64-Bit Server VM SapMachine (build 18+36-sapmachine, mixed mode)

There might be multiple versions installed, and this version is not supporting the project. So I still need to install the correct version.

If your operating system is macOS or Linux, you can use Homebrew to install java, first update brew,

brew update
brew tap AdoptOpenJDK/openjdk

and then install Java 8

brew install adoptopenjdk8 --cask

➡️ Install Maven

Check if maven is installed.

mvn --version

Result,

Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0)
Maven home: /Users/xyz/Workspace/apache-maven-3.8.5
Java version: 18, vendor: SAP SE, runtime: /Library/Java/JavaVirtualMachines/sapmachine-jdk-18.jdk/Contents/Home
Default locale: en_CN, platform encoding: UTF-8
OS name: "mac os x", version: "12.4", arch: "aarch64", family: "mac"

If not, first download the maven latest release and then install it.

In my case maven is installed but the default java version is not correct. This is because the Java home is still the old one.

echo $JAVA_HOME

get result:

/Library/Java/JavaVirtualMachines/sapmachine-jdk-18.jdk/Contents/Home

So after finding the java home, set new java home. In my case:

export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

Now both the java version and maven default java version are correct.

java -version
# result
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.292-b10, mixed mode)
mvn --version
# result
Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0)
Maven home: /Users/xyz/Workspace/apache-maven-3.8.5
Java version: 1.8.0_292, vendor: AdoptOpenJDK, runtime: /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre
Default locale: en_CN, platform encoding: UTF-8


OS name: "mac os x", version: "10.16", arch: "x86_64", family: "mac"

If you want to make the change permanent, write it in /usr/local/etc/mavenrc or /etc/mavenrc

➡️ Install eclipse and eclipse maven plugin

Install eclipse by following the steps on this page.

In my case eclipse is installed, so open the eclipse, go to the Eclipse Marketplace and search for the maven plugin: M2Eclipse – Eclipse IDE integration for Maven. For terminal you can use the Terminal desktop app or install a terminal plug-in in eclipse.

➡️ Install cf cli

Install the command-line interface for Cloud Foundry, see here.

In my case it is installed, check version,

cf -v

get result

cf version 8.1.0+034d929d7.2022-01-03

Initiate the project

➡️ Generate project from archetype

Use maven to generate a Cloud SDK project, from the “hello world” archetype,

mvn archetype:generate -DarchetypeGroupId=com.sap.cloud.sdk.archetypes -DarchetypeArtifactId=scp-cf-tomee -DarchetypeVersion=RELEASE

and then fill in the requested info in the interactive session, e.g. name – firstapp. If you want to use the default setting then just hit return.

The archetype is a TomEE-based project, scp-cf-tomee, latest version 4.0.0.

Import the newly created project into eclipse.

➡️ Build the project

Go into the project root path and build the project,

mvn clean package

with this command an *.war file will be generated.

You can run the project locally, with TomEE container as its target runtime,

mvn tomee:run -pl application

and then visit  http://localhost:8080/hello

➡️ Deploy to cf

It can run on both neo and cloud foundry. First login to cf with the user credentials and API endpoint URL, in my case I found https://api.cf.sap.hana.ondemand.com in my Subaccount.

cf login -a https://api.cf.sap.hana.ondemand.com -u sindy.zhan@sap.com -p XYZ

Then specify the ORG and SPACE, and deploy the app,

cf push

You can check the deployed app and its route, which you use to access the app.

cf apps
# result
Getting apps in org XYZ / space XYZ as sindy.zhan@sap.com...

name       requested state   processes   routes
firstapp   started           web:1/1     firstapp-fearless-chipmunk-vf.cfapps.sap.hana.ondemand.com

In my case, I can visit the app via https://firstapp-fearless-chipmunk-vf.cfapps.sap.hana.ondemand.com

Click HelloWorldServlet, or add a path /hello at the end of the URL to see the “hello world” greeting.

Retrieve data from the backend

The above steps bring us a demo hello world module, displaying static text on the webpage. Now we will create a new module to connect to the backend system.

➡️ Add business partner servlet

Create BusinessPartnerServlet, to retrieve all persons (a specific kind of business partner) with their name and a few additional properties. You can copy and paste the code from the original tutorial, which needs some changes according to your scenario, or you can follow this blog post and copy and paste the code below.

package com.sap.cloud.sdk.tutorial;

import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor;
import com.sap.cloud.sdk.datamodel.odata.client.exception.ODataException;
import com.sap.cloud.sdk.datamodel.odata.helper.Order;

import com.sap.cloud.sdk.s4hana.connectivity.DefaultErpHttpDestination;
import com.sap.cloud.sdk.s4hana.connectivity.ErpHttpDestination;
import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.businesspartner.BusinessPartner;
import com.sap.cloud.sdk.s4hana.datamodel.odata.services.DefaultBusinessPartnerService;

@WebServlet("/businesspartners")
public class BusinessPartnerServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private static final Logger logger = LoggerFactory.getLogger(BusinessPartnerServlet.class);

    private static final String CATEGORY_PERSON = "1";
    private final ErpHttpDestination destination = DestinationAccessor.getDestination("MyErpSystem").asHttp().decorate(DefaultErpHttpDestination::new);

    @Override
    protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {
        try {
            final List<BusinessPartner> businessPartners =
                    new DefaultBusinessPartnerService()
                            .getAllBusinessPartner()
                            .select(BusinessPartner.BUSINESS_PARTNER,
                                    BusinessPartner.LAST_NAME,
                                    BusinessPartner.FIRST_NAME,
                                    BusinessPartner.IS_MALE,
                                    BusinessPartner.IS_FEMALE,
                                    BusinessPartner.CREATION_DATE)
                            .filter(BusinessPartner.BUSINESS_PARTNER_CATEGORY.eq(CATEGORY_PERSON))
                            .orderBy(BusinessPartner.LAST_NAME, Order.ASC)
                            .top(200)
                            .executeRequest(destination);

            logger.info(String.format("Found %d business partner(s).", businessPartners.size()));

            response.setContentType("application/json");
            response.getWriter().write(new Gson().toJson(businessPartners));
        } catch (final ODataException e) {
            logger.error(e.getMessage(), e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.getWriter().write(e.getMessage());
        }
    }
}

Connect to OData service

➡️ Choose OData service

Here the OData service is SAP S/4HANA cloud with Business Partner OData V2 service.

➡️ Expose APIs on SAP S/4HANA cloud

To expose APIs on SAP S/4HANA cloud, then you should create communication users, and create destination

0. search for communication scenario

On SAP API Business Hub, we find the information for Business Partner (A2X): https://api.sap.com/api/API_BUSINESS_PARTNER/overview

You can click on the business document to see APIs and their sample playloads.

Here we will use a sample URL read Business Partner master data:

GET /sap/opu/odata/SAP/API_BUSINESS_PARTNER/A_BusinessPartner(BusinessPartner=’900023122′)

You can also find the Communication Scenario we need: Business Partner, Customer and Supplier Integration(SAP_COM_0008)

 

And then In S/4HANA Cloud, Fiori Launchpad, we complete the rest of the steps to expose APIs.

1. create communication user

Search for communication user > open “Maintain Communication Users” tile  > click New > fill in the user name,

Do remember to note down the generated password for later use.

Then click Create.

2. create communication system

Navigate to Communication Systems > New > input System ID and System Name.

In the Technical Data > General, fill in Host Name. In my case, the host name to my S/4HANA Cloud system is my301481.s4hana.ondemand.com, so I set my host name to be my301481-api.s4hana.ondemand.com

Choose the Communication User we just created for New Inbound Communication User

And for the Outbound Communication, choose the default customer client certificate

 

Save the changes.

3. create communication arrangement

Search for and navigate to Communication Arrangements > create New > fill in the Communication Scenario that we need SAP_COM_0008.

Select Communication System we just created, and the associated Communication User automatically comes in.

In the Inbound Services section, we can find the Service URL for Business Partner (A2X) OData V2

Business Partner (A2X) OData V2 https://my301481-api.s4hana.ondemand.com/sap/opu/odata/sap/API_BUSINESS_PARTNER

In the Outbound Services section, dis-select the outbound services that are active by default.

Save it.

~. test it on postman (or other tools)

This is an optional step.

If we want to read the list of business partners, create request:

GET https://my301481-api.s4hana.ondemand.com/sap/opu/odata/sap/API_BUSINESS_PARTNER/A_BusinessPartner

And fill in the authorization: Authorization > Type > choose Basic Auth > fill in communication user as Username and Password

 

From the response body we can find a Business Partner ID, and use it to read the corresponding business partner details. In my case I check the Business Partner with the ID 1000154,

GET https://my301481-api.s4hana.ondemand.com/sap/opu/odata/sap/API_BUSINESS_PARTNER/A_BusinessPartner('1000154')

➡️ Configurate destination on BTP

If you want to deploy the app to Cloud Foundry, go to your BTP Cockpit > Subaccount > Connectivity > Destinations.

Create a new destination with the name of MyErpSystem (which is hardcoded in BusinessPartnerServlet.java), URL to be https:// = host name, and choose BasicAuthentication, with the Communication User credentials to be User and Password.

After creation, you can test the connection. Every HTTP status code below 500 is treated as successful.

Deploy to the cloud

Now go back from BTP Cockpit to local Terminal, and do the deployment.

➡️ Create two service instance

Create service instance for the destination service and xsuaa. You can do it in cf cli or in Cockpit, here we provide the cf cli commands:

cf create-service destination lite my-destination
cf create-service xsuaa application my-xsuaa

➡️ Bind the app with two newly created service instances

To bind the two newly created service instances to your application when it is deployed, adapt the manifest.yml file by adding the two instances to the services section at the end.

In this case, the two services are commented in manifest.yml so now uncomment them.

➡️ Deploy to SAP BTP Cloud Foundry

Now deploy the application again.

mvn clean install
cf push

Use the same URL we can visit the application, but this time a new servlet can be accessed via path /businesspartners

The rest of the tutorial is to add a local integration test in the integration-test module, which doesn’t affect the above steps so I will not add them to this blog post. If necessary, I will complete them later.

Assigned Tags

      6 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Gregor Wolf
      Gregor Wolf

      Hi Sindy,

      I would think that directly improving the tutorial by getting in touch with the Team by filing an issue in the https://github.com/sap-tutorials/Tutorials reporitory would be more beneficial.

      Best Regards
      Gregor

      Author's profile photo Sindy Zhan
      Sindy Zhan
      Blog Post Author

      Hi Gregor,

      Thank you for providing a way to improve the tutorials in developer community!

      I think the original tutorial is very good. My blog post is only to complement the connect to s/4hana cloud part, as one of the possible implementations. So I guess it is not an issue?

      BR,

      Sindy

      Author's profile photo Gregor Wolf
      Gregor Wolf

      I still would suggest to reach out. In the meantime you might add this as an additional information at the beginning of your post.

      Author's profile photo Sindy Zhan
      Sindy Zhan
      Blog Post Author

      Hi Gregor,

      Thank you for your advice! I made it clearer at the beginning of the post.

      Best regards,

      Sindy

      Author's profile photo Matthias Kuhr
      Matthias Kuhr

      Hi Sindy, thank you for writing this post! Regarding Gregors suggestion, we'll probably add a a note in the tutorial when we next update it. The note would be referring to the documentation on how to set up the communication scenario and also include a link to this blog post.

      Also, we just released version 4 of the SAP Cloud SDK for Java. This blog post and the tutorial should both work just fine with version 4. However, the screenshot above still shows version 3.74 on Maven Central. If you don't mind and have a minute, maybe you could update the screenshot so that it feels up to date 😉

      Thanks again for the great blog post!

      Author's profile photo Sindy Zhan
      Sindy Zhan
      Blog Post Author

      Hi Matthias,

      Thank you for your reply! Your tutorial is already very detailed and helpful!

      Thank you also for improving SAP Cloud SDK for Java. I have made the updates according to your reply.

      BR,

      Sindy