Java develoment for SAP Cloud Platform

In this blog series I will show you how the Java development for the SAP Cloud Plaform is done based on Spring Boot. Spring Boot is the defacto standard framework for developing Java applications in the Cloud / Software-as-a-Service.

There are many resources available on the Internet for development with Spring Boot, but the SAP Cloud Platform specifics mostly fell by the wayside. SAP offers an SDK in the neo stack of the SAP Cloud Platform that enables the use of SAP’s own functionalities in Java. This blog focuses on the general developer tasks in the development of Java applications. The structure of the pom.xml is shown and a simple rest controller is implemented.

I will show the following contents in future blogs:

  • Access HANA DB via JNDI
  • Access Destinations via JNDI
  • Access Tenant Information via JNDI
  • Access User Information

pom.xml Structure

The pom.xml contains all relevant information required to build the application.

Parent

After we set to Spring Boot this must be defined as parent.

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.1.RELEASE</version>
  <relativePath />
</parent>

Properties

The Java version and the version of the SAP Cloud SDK are defined in the properties.

<properties>
  <java.version>1.8</java.version>
  <sap.cloud.sdk.version>3.107.18</sap.cloud.sdk.version>
</properties>

Dependencies

In the dependencies the dependencies are defined. Among other things, references are made to SpringBoot Starter Web and also to the SAP Cloud SDK. With the SAP Cloud SDK it is important that the link is to the version defined in the properties and that the scope is set to the value provided. This means that this dependency is not packed in the WAR file and is considered as provided to the server.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId> 
</dependency>
<dependency> 
  <groupId>com.sap.cloud</groupId>
  <artifactId>neo-java-web-api</artifactId>
  <version>${sap.cloud.sdk.version}</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.6</version>
</dependency>

Profile

In this example, a separate profile is created for the deployment on the neo stack. This profile defines that certain dependencies are provided by the server and are not embedded in the WAR file. Otherwise the start of the application would fail.

<profile>
  <id>neo</id>
  <activation>
    <activeByDefault>true</activeByDefault>
  </activation>
  <properties>
    <packaging.type>war</packaging.type>
  </properties> 
  <dependencies> 
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <scope>provided</scope>
    </dependency>  
  </dependencies>
</profile>

Build Plugins

Finally, the Spring Boot Maven plugin must be defined in the build.

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

Build the application for the SAP Cloud Platform

The build of the application can be executed via the CommandLine with the following command

mvn clean package -Pneo

In order to successfully launch the application from within Tomcat, the configure method must be redefined from the SpringBootServletInitializer. This can be done either directly in the main class of the application or in a separate class. Personally I prefer to use my own class at this point.

package at.clouddna.demo;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(DocmgmtApplication.class);
  }
}

Implementation of a simple rest controller

So that a functional test can be carried out, I always implement a ping method in a separate controller.

package at.clouddna.docmgmt.controller; 
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.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 
@RestController 
@RequestMapping({ "/ping" }) 
public class PingController { 
  private static final Logger logger = LoggerFactory.getLogger(PingController.class); 
  @GetMapping
  public ResponseEntity<?> ping() { 
    logger.debug("ping called"); 
    return ResponseEntity.ok("Hello World"); 
  }
}

This means we are already finished with a simple application. When deploying via the SAP Cloud Platform Cockpit, make sure that the Java Web Tomcat 8 Runtime is selected and that the profile is transferred as a JVM parameter as follows

-Dspring.profiles.active=neo

The ping controller can be tested directly from the browser, since the corresponding method is called via an HTTP GET request.