Skip to Content

Background

Before we start using Spring or Spring Boot into a Java Application to be deployed no SAP Cloud Platform Neo we need to clear out some important information.

Don’t think about Neo Java Runtime as being the same as a Tomcat Server

Neo is based on a Tomcat container, but it isn’t the same as a full-blown Tomcat. A Tomcat Server is a Java EE system that contains more features that those provided by the Neo runtime. Furthermore, it allows additional configuration of the runtime that will demand administrator rights into its installation filesystem – such similar actions can only be accomplished by the SAP Cloud Cockpit or Neo Command Line Tools in the case of a Neo Application. Additionally, Neo will allow you to run your application in a single container. In other words, it will not allow you to deploy multiple WAR files to the same server instance. Since there are many conceptual differences between the two, we need to make some thoughtful considerations while porting a Tomcat application to Neo (will disclose those further down this blog).

A Spring application is defined differently in Neo, but not on Cloud Foundry

On a CF environment the only thing available to you is the Java build pack – which provides you with a complete Java Standard Edition runtime filesystem. Therefore, you must specify which JEE Container you wish to use for a Java application. Thus, the Spring Boot Starter Web package makes a lot of sense in the CF context. That is, you do not have to think about installing a Tomcat service since Spring Boot already provides one to you.

Consider the following

Avoid using the same Java libraries that are already included in the Neo SDK.

I highly encourage the usage of the Neo SDK to develop Java apps to be fully compatible with Neo. Keep in mind that each Neo SDK contains a stripped-down version of Tomcat or Web Profile and they all comply with the JEE standards. Therefore, you need to choose one SDK over the other to be able to use this or that specification. Check this out (https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/7613bd28711e1014839a8273b0e91070.html). Once you choose the SDK version, you may add libraries to your project.

Give precedence to the java libraries included in the Neo SDK

Unless you really know the internal consequences, excluding a jar file from the Neo SDK to allow another library version or even a complete re-implementation of the JEE specification by 3rd party libraries are discouraged. It is better to keep the usage of the libraries included in the Neo SDK and exclude the same implementation from other packages such as those provided by Spring Boot (i.e.: spring-boot-starter-web already contains an embedded Tomcat container which is basically the same thing Neo SDK is doing for you – the same goes for SFL4J). By doing so, you ensure that you are using same runtime environment that is to be found on SAP Cloud Platform while testing your application locally. Which in turn allows you to deploy your application less frequently into the cloud to make sure your application runs.

Configuring a Spring Application for Neo runtime

Create a simple Spring Boot application (I prefer using the Spring IDE to create my project but you could also be using Initializr (https://start.spring.io) or some other preferred method).

Make sure your project has the starter Web dependency:

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

However, there is no need for the starter tomcat package, so it is safe to remove it now:

<!-- 		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency> -->

Add the following dependency to include the Neo Runtime for Java Web Tomcat 8 (make sure you define the SDK version in the properties session):

<dependency>
  <groupId>com.sap.cloud</groupId>
  <artifactId>neo-java-web-sdk</artifactId>
  <version>${sap.cloud.sdk.version}</version>
  <scope>provided</scope>
</dependency>

Here is an example for Java Web Tomcat 8 runtime (version 3.x is Tomcat 8):

<properties>
  <sap.cloud.sdk.version>3.54.23</sap.cloud.sdk.version>
</properties>

While running it locally as a Java application or Spring Application doesn’t present any issues. However, the java class loader in such cases are very different from the one used by SAP Cloud Platform to start your application. If you leave it at that, your project will not run in the cloud and will probably throw an exception like this:

ERROR org.slf4j.helpers.Util - SLF4J: Class path contains multiple SLF4J bindings.
ERROR org.slf4j.helpers.Util - SLF4J: Found binding in [jar:file:/tom8/repository/.archive/bin/logback-classic.jar!/org/slf4j/impl/StaticLoggerBinder.class]
ERROR org.slf4j.helpers.Util - SLF4J: Found binding in [jar:file:/wtpwebapps/coil.spring.app1/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
ERROR org.slf4j.helpers.Util - SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
17:03:39.138 [localhost-startStop-1] ERROR org.slf4j.helpers.Util - SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

It is clear here that the SLF4J is declared both by Spring Boot Starters and by the Neo runtime. Therefore, we need to remove dependency from our POM file, since there is no way to remove it from SCP itself. However, if we simply remove it the compilation may fail. Therefore we need to re-define it as being provided by something else in the POM. Here is how we do it:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<!-- Some exclusions are necessary to make Spring Boot run on SCP. -->
			<exclusions>
				<exclusion>
					<groupId>ch.qos.logback</groupId>
					<artifactId>logback-classic</artifactId>
				</exclusion>
			</exclusions>			
		</dependency>
		<!-- Log requirements being provided by Neo SDK-->
		<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>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-core</artifactId>
			<scope>provided</scope>
		</dependency>

Running a Neo/Spring Application locally

Using the SCP Eclipse plugin you are able to create a server configuration to deploy your application directly via Eclipse.

First, download the SDK from https://tools.hana.ondemand.com/#cloud . Here I will be using the Java Web Tomcat 8 version.

Extract it into a folder of your choice.

Open Eclipse and select new à server from the context menu by right-clicking on the blank part of the servers tab

Select SAP Java Web Tomcat 8 (you will be prompted to select the installation folder which is the folder where you extracted the SDK)

 

 

After the server is created, double-click on it to open the configuration pane. Then open the Timeouts session and change the startup time to 120

Save the configuration file for this local server.

I am not going to teach you how to create a simple Spring Boot Application. Here I am using the simplest for of Spring Boot application (a simple servlet that says hello).

After you have your application tested in standalone mode you may add it as a web-module to your local Java Web Tomcat 8 server defined in Eclipse. Follow the steps below:

Once you start the local server the icon and text will change like following screen – stating: “Started, Synchronized”. To load all of the features specific to the Cloud Platform and start the Spring Boot application the whole process should take longer than the standard 45 seconds. This is the reason why we have changed to 120 seconds. You may need to increase this time when running the same process on a slower machine. It might also not be required at all because it depends on your machine’s performance.

Right-click the application and copy the application link to open in the external browser or open it directly on the integrated browser:

The result should be your application’s starting page, like so:

Differences between SCP and Local Runtime.

  • First, the Java Runtime will most likely not be the same. You may choose to run the application locally with Sun’s JRE while others may choose SAP’s JRE and it all may as well be on different revisions. On SCP it will also be true. Check the JVM that is available on each runtime. For instance: applications running on Java Web Tomcat 8 SDK will be installed on SCP with JVM 1.8.
  • Application’s URL running locally can be accessed via local IP, localhost or local machine. On SCP it will be composed of sub-account name and application id.
  • While running the application in standalone mode the application context isn’t defined. So, there is no suffix added to it. However, by deploying it on either the local server or on SCP a suffix will be added to it. The context name will be composed by the same name as the deployment unit name (WAR Filename). It is possible to deploy your app without this “add-context” – thus avoid the suffix altogether – by defining the WAR file name as ROOT.WAR, regardless of the application name you use during deployment.

 

Enjoy,
Ivan

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply