Build a Java Spring boot middleware application to consume SAP OData service with SAP Cloud SDK

Estimated read time 20 min read

Introduction

We had a requirement to consume a SAP OData service in an existing spring boot application running on SAP BTP Cloud Foundry. There are many ways to consume an OData service in a Java application, but we found an easier way to consume the OData service by using SAP Cloud SDK. There are many business use cases where we need to develop an application to run on SAP BTP or any cloud and consume OData service.  In this blog, I will share the steps to consume an OData service in a maven-based Java Spring boot application with the help of SAP Cloud SDK.

Understanding SAP Cloud SDK

SAP provides a software development kit (SDK) called the SAP Cloud SDK to make developers’ jobs easier. The SDK contains a set of libraries that simplify interacting with APIs at a higher level by hiding technical communication details.

The SAP Cloud SDK was developed to reduce the effort of building extension applications for SAP S/4HANA Cloud. It provides Java and JavaScript libraries, as well as a set of tools for developers, such as fault tolerance, cache management, tutorials, and project templates.

The SAP Cloud SDK enables partners, customers to easily consume OData services from SAP S/4HANA Cloud, discover existing OData services, and use built-in developer tools such as cache management, API metering, latency, and fault tolerance.

SAP Cloud SDK also allows you to generate the Virtual Data Model (VDM) of custom OData Services as well as standard SAP OData Services.  This VDM can then be readily consumed by your application

SAP CAP Model uses SAP Cloud SDK behind the scenes to perform a variety of tasks.

Business use cases

Scenario 1:- If you are planning to build your application using MongoDB, then you will not be able to use the CAP Model (since it only supports HANA for production), so you can create an application(MTA) in Java Spring boot and make use of SAP Cloud SDK for connecting to remote systems, consuming APIs in a type-safe manner, securing your application and providing multi-tenant support, etc.Scenario 2: – If you already have an existing Java application that was built without using the SAP CAP Model and you want to add more features like consuming an OData service.Scenario 3: – If you need advanced features in your app (currently, not provided by CAP Model) – for example, Resilience. Scenario 4: – You Are Extending an SAP Product or Service, building a Middle-Ware, Publishing a Cloud App

Steps at a high level

Create a maven-based Java Spring boot application/project.Download the metadata of the service and save it as “serviceName.edmx”.Put the EDMX file in the resource folder of the application/project.(optional) Create a service naming properties file in the resource folder.Add the dependencies (SAP Cloud SDK OData generator and others) in the pom.xml file.Add the OData generator maven plugin in the pom.xml file.Compile the application to generate the type-safe Java client library from the EDMX of the service, which gives you programmatic access to all the entities, fields, and structures of the OData serviceCreate the controller class and use the generated classes to interact with the OData service.Create the destination in the environment variable for local testing and in the BTP for productive use.Run the application and test it locally.Deploy the application to BTP Cloud Foundry as an MTA application.

Prerequisite

Eclipse(with Spring tool suite and Lombok plugin)JDK(1.8).Access to any OData service (I will be using Business Partner API from SAP Business Accelerator Hub)  

(In this blog I will not cover the BTP deployment, I will explain how to test the application locally.  Please refer to my other blog for deployment to BTP Cloud Foundry)

Steps

Create a new spring boot project in Eclipse as mentioned below.

The project structure in eclipse will look like below.

Open the pom.xml file and replace the below code.

 

<?xml version=”1.0″ encoding=”UTF-8″?>
<project xmlns=”http://maven.apache.org/POM/4.0.0″
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd”>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath /> <!– lookup parent from repository –>
</parent>
<groupId>com.sl</groupId>
<artifactId>SpringBootToConsumeODataThroughCloudSDK</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootToConsumeODataThroughCloudSDK</name>
<description>Sample Spring Boot App to consume OData through Cloud SDK</description>
<url />
<licenses>
<license />
</licenses>
<developers>
<developer />
</developers>
<scm>
<connection />
<developerConnection />
<tag />
<url />
</scm>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>

<dependency>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-core</artifactId>
<version>4.15.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-generator-maven-plugin</artifactId>
<!– Please use the latest version here –>
<version>4.15.0</version>
<executions>
<execution>
<id>generate-consumption</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputDirectory>${project.basedir}/src/main/resources/edmx</inputDirectory>
<outputDirectory>${project.build.sourceDirectory}</outputDirectory>
<serviceNameMappingFile>${project.basedir}/src/main/resources/serviceNameMappings.properties</serviceNameMappingFile>
<deleteOutputDirectory>false</deleteOutputDirectory>
<packageName>com.sl.vdm</packageName>
<defaultBasePath>odata/v2/</defaultBasePath>
<compileScope>COMPILE</compileScope>
<serviceMethodsPerEntitySet>true</serviceMethodsPerEntitySet>
<overwriteFiles>true</overwriteFiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>

 

(In this blog we will be using OData V2 and SAP Cloud SDK version 4, if you want to consume OData V4 then the dependency version needs to be changed in the pom.xml file)

Go to SAP Business Accelerator Hub to download the metadata of the OData service.Search for “business” in the search box for business partner OData service (In this blog we will be using OData V2).

 

(Please login with your personal(trial) SAP user account)

Click on “Business Partner (A2X)” to navigate to business partner API.Click on “API Specification” and download the EDMX (service metadata).

 

(If you want to consume an OData service that is not available in the Business Accelerator Hub like On-promise ECC/S4HANA OData service then you can fetch the metadata of the service by using $metadata and save the content in a .edmx file{any name})

Create a folder called “edmx” in the resource folder of the project and copy the downloaded/created edmx file.Also create a properties file “serviceNameMappings.properties” in the resource folder.

 

# API BUSINESS PARTNER
API_BUSINESS_PARTNER.className = APIBusinessPartner
API_BUSINESS_PARTNER.packageName = businesspartner

 

 Now the folder structure in Eclipse should look like below.

Now compile the project by using the “maven install” command.

Once the project is compiled successfully it will generate the classes for the OData service which will be used in our business logic for integration with the OData service.Now the folder structure should look like below in Eclipse.

(Sometimes it doesn’t create the correct URL in the generated service interface (APIBusinessPartnerService,java), so please verify and replace it with the correct URL as mentioned below. You can find the correct URL when you click “Code Snippet” in the “Try Out” tab in Business Accelerator Hub)

 

String DEFAULT_SERVICE_PATH = “odata/sap/API_BUSINESS_PARTNER”;

 

Now create a controller class (BusinessPartnerController.java) to fetch business partners.Replace the below code in the BusinessPartnerController class.

 

package com.sl.api;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.gson.Gson;
import com.sap.cloud.sdk.cloudplatform.connectivity.Destination;
import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor;
import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination;
import com.sl.vdm.namespaces.businesspartner.BusinessPartner;
import com.sl.vdm.services.DefaultAPIBusinessPartnerService;

@RestController
public class BusinessPartnerController {

private final Logger log = LoggerFactory.getLogger(this.getClass());
private static final String APIKEY_HEADER = “apikey”;
private static final String SANDBOX_APIKEY = “—Generated API Key—“;

@GetMapping(“/GetBusinessPartners”)
public ResponseEntity<?> getBusinessPartners() {
String DESTINATION_NAME = “MyDestination”; // in productive code, use constants file to
// retrieve destination name
HttpDestination destination =
DestinationAccessor.getDestination(DESTINATION_NAME).asHttp();

final List<BusinessPartner> businessPartners = new DefaultAPIBusinessPartnerService()
.getAllBusinessPartner().select(BusinessPartner.BUSINESS_PARTNER, BusinessPartner.LAST_NAME,
BusinessPartner.FIRST_NAME, BusinessPartner.CREATED_ON)
.filter(BusinessPartner.MALE.eq(true))
.top(200)
.withHeader(APIKEY_HEADER, SANDBOX_APIKEY)
.executeRequest(destination);

return ResponseEntity.ok( new Gson().toJson(businessPartners));
}
}

 

Generate the API key from Business Accelerator Hub and copy it in the variable SANDBOX_APIKEY in BusinessPartnerController class.

(If the OData service is from other system like ECC or S4HANA then this step is not required, and the authentication will be set in the destination which will be automatically picked up by the SAP Cloud SDK library)

 Now we need to create a destination in the environment variable to configure the OData service URL and authentication details (in this case authentication is not required).Right-click on the project and select the run configuration, select the “Environment” tab in the dialogue box.Click on “Add” to create an environment variable for the destination. Keep the name as “destinations” and value as mentioned below.

 

[{“name”: “MyDestination”, “url”: “https://sandbox.api.sap.com/s4hanacloud/sap/opu/”}]

 

<<sample destination with basic authentication>>

[{“name”: “MyDestination”, “url”: “–OData service base URL–“, “name”: “user name”, “password”: “password for the given user” }]

(You can add multiple destinations to connect to different systems)

Click on apply and run.If everything is fine, then it will be a success and show the port number for the App.Now you can test it from your browser by using the application URL

Note :- This blog is written based on my personal leraning, please feel free to commnet for improvement.

Happy learning!!

Best Regards,

Sudhir.

 

​ IntroductionWe had a requirement to consume a SAP OData service in an existing spring boot application running on SAP BTP Cloud Foundry. There are many ways to consume an OData service in a Java application, but we found an easier way to consume the OData service by using SAP Cloud SDK. There are many business use cases where we need to develop an application to run on SAP BTP or any cloud and consume OData service.  In this blog, I will share the steps to consume an OData service in a maven-based Java Spring boot application with the help of SAP Cloud SDK.Understanding SAP Cloud SDKSAP provides a software development kit (SDK) called the SAP Cloud SDK to make developers’ jobs easier. The SDK contains a set of libraries that simplify interacting with APIs at a higher level by hiding technical communication details.The SAP Cloud SDK was developed to reduce the effort of building extension applications for SAP S/4HANA Cloud. It provides Java and JavaScript libraries, as well as a set of tools for developers, such as fault tolerance, cache management, tutorials, and project templates.The SAP Cloud SDK enables partners, customers to easily consume OData services from SAP S/4HANA Cloud, discover existing OData services, and use built-in developer tools such as cache management, API metering, latency, and fault tolerance.SAP Cloud SDK also allows you to generate the Virtual Data Model (VDM) of custom OData Services as well as standard SAP OData Services.  This VDM can then be readily consumed by your applicationSAP CAP Model uses SAP Cloud SDK behind the scenes to perform a variety of tasks.Business use casesScenario 1:- If you are planning to build your application using MongoDB, then you will not be able to use the CAP Model (since it only supports HANA for production), so you can create an application(MTA) in Java Spring boot and make use of SAP Cloud SDK for connecting to remote systems, consuming APIs in a type-safe manner, securing your application and providing multi-tenant support, etc.Scenario 2: – If you already have an existing Java application that was built without using the SAP CAP Model and you want to add more features like consuming an OData service.Scenario 3: – If you need advanced features in your app (currently, not provided by CAP Model) – for example, Resilience. Scenario 4: – You Are Extending an SAP Product or Service, building a Middle-Ware, Publishing a Cloud AppSteps at a high levelCreate a maven-based Java Spring boot application/project.Download the metadata of the service and save it as “serviceName.edmx”.Put the EDMX file in the resource folder of the application/project.(optional) Create a service naming properties file in the resource folder.Add the dependencies (SAP Cloud SDK OData generator and others) in the pom.xml file.Add the OData generator maven plugin in the pom.xml file.Compile the application to generate the type-safe Java client library from the EDMX of the service, which gives you programmatic access to all the entities, fields, and structures of the OData serviceCreate the controller class and use the generated classes to interact with the OData service.Create the destination in the environment variable for local testing and in the BTP for productive use.Run the application and test it locally.Deploy the application to BTP Cloud Foundry as an MTA application.Prerequisite Eclipse(with Spring tool suite and Lombok plugin)JDK(1.8).Access to any OData service (I will be using Business Partner API from SAP Business Accelerator Hub)  (In this blog I will not cover the BTP deployment, I will explain how to test the application locally.  Please refer to my other blog for deployment to BTP Cloud Foundry)StepsCreate a new spring boot project in Eclipse as mentioned below.The project structure in eclipse will look like below.Open the pom.xml file and replace the below code. <?xml version=”1.0″ encoding=”UTF-8″?>
<project xmlns=”http://maven.apache.org/POM/4.0.0″
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd”>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath /> <!– lookup parent from repository –>
</parent>
<groupId>com.sl</groupId>
<artifactId>SpringBootToConsumeODataThroughCloudSDK</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootToConsumeODataThroughCloudSDK</name>
<description>Sample Spring Boot App to consume OData through Cloud SDK</description>
<url />
<licenses>
<license />
</licenses>
<developers>
<developer />
</developers>
<scm>
<connection />
<developerConnection />
<tag />
<url />
</scm>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>

<dependency>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-core</artifactId>
<version>4.15.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-generator-maven-plugin</artifactId>
<!– Please use the latest version here –>
<version>4.15.0</version>
<executions>
<execution>
<id>generate-consumption</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputDirectory>${project.basedir}/src/main/resources/edmx</inputDirectory>
<outputDirectory>${project.build.sourceDirectory}</outputDirectory>
<serviceNameMappingFile>${project.basedir}/src/main/resources/serviceNameMappings.properties</serviceNameMappingFile>
<deleteOutputDirectory>false</deleteOutputDirectory>
<packageName>com.sl.vdm</packageName>
<defaultBasePath>odata/v2/</defaultBasePath>
<compileScope>COMPILE</compileScope>
<serviceMethodsPerEntitySet>true</serviceMethodsPerEntitySet>
<overwriteFiles>true</overwriteFiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project> (In this blog we will be using OData V2 and SAP Cloud SDK version 4, if you want to consume OData V4 then the dependency version needs to be changed in the pom.xml file)Go to SAP Business Accelerator Hub to download the metadata of the OData service.Search for “business” in the search box for business partner OData service (In this blog we will be using OData V2). (Please login with your personal(trial) SAP user account)Click on “Business Partner (A2X)” to navigate to business partner API.Click on “API Specification” and download the EDMX (service metadata). (If you want to consume an OData service that is not available in the Business Accelerator Hub like On-promise ECC/S4HANA OData service then you can fetch the metadata of the service by using $metadata and save the content in a .edmx file{any name})Create a folder called “edmx” in the resource folder of the project and copy the downloaded/created edmx file.Also create a properties file “serviceNameMappings.properties” in the resource folder. # API BUSINESS PARTNER
API_BUSINESS_PARTNER.className = APIBusinessPartner
API_BUSINESS_PARTNER.packageName = businesspartner  Now the folder structure in Eclipse should look like below.Now compile the project by using the “maven install” command.Once the project is compiled successfully it will generate the classes for the OData service which will be used in our business logic for integration with the OData service.Now the folder structure should look like below in Eclipse.(Sometimes it doesn’t create the correct URL in the generated service interface (APIBusinessPartnerService,java), so please verify and replace it with the correct URL as mentioned below. You can find the correct URL when you click “Code Snippet” in the “Try Out” tab in Business Accelerator Hub) String DEFAULT_SERVICE_PATH = “odata/sap/API_BUSINESS_PARTNER”; Now create a controller class (BusinessPartnerController.java) to fetch business partners.Replace the below code in the BusinessPartnerController class. package com.sl.api;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.gson.Gson;
import com.sap.cloud.sdk.cloudplatform.connectivity.Destination;
import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor;
import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination;
import com.sl.vdm.namespaces.businesspartner.BusinessPartner;
import com.sl.vdm.services.DefaultAPIBusinessPartnerService;

@RestController
public class BusinessPartnerController {

private final Logger log = LoggerFactory.getLogger(this.getClass());
private static final String APIKEY_HEADER = “apikey”;
private static final String SANDBOX_APIKEY = “—Generated API Key—“;

@GetMapping(“/GetBusinessPartners”)
public ResponseEntity<?> getBusinessPartners() {
String DESTINATION_NAME = “MyDestination”; // in productive code, use constants file to
// retrieve destination name
HttpDestination destination =
DestinationAccessor.getDestination(DESTINATION_NAME).asHttp();

final List<BusinessPartner> businessPartners = new DefaultAPIBusinessPartnerService()
.getAllBusinessPartner().select(BusinessPartner.BUSINESS_PARTNER, BusinessPartner.LAST_NAME,
BusinessPartner.FIRST_NAME, BusinessPartner.CREATED_ON)
.filter(BusinessPartner.MALE.eq(true))
.top(200)
.withHeader(APIKEY_HEADER, SANDBOX_APIKEY)
.executeRequest(destination);

return ResponseEntity.ok( new Gson().toJson(businessPartners));
}
} Generate the API key from Business Accelerator Hub and copy it in the variable SANDBOX_APIKEY in BusinessPartnerController class.(If the OData service is from other system like ECC or S4HANA then this step is not required, and the authentication will be set in the destination which will be automatically picked up by the SAP Cloud SDK library) Now we need to create a destination in the environment variable to configure the OData service URL and authentication details (in this case authentication is not required).Right-click on the project and select the run configuration, select the “Environment” tab in the dialogue box.Click on “Add” to create an environment variable for the destination. Keep the name as “destinations” and value as mentioned below. [{“name”: “MyDestination”, “url”: “https://sandbox.api.sap.com/s4hanacloud/sap/opu/”}] <<sample destination with basic authentication>>[{“name”: “MyDestination”, “url”: “–OData service base URL–“, “name”: “user name”, “password”: “password for the given user” }](You can add multiple destinations to connect to different systems)Click on apply and run.If everything is fine, then it will be a success and show the port number for the App.Now you can test it from your browser by using the application URLNote :- This blog is written based on my personal leraning, please feel free to commnet for improvement.Happy learning!!Best Regards,Sudhir.   Read More Technology Blogs by Members articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author