Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Raja
Product and Topic Expert
Product and Topic Expert

Disclaimer: This blog post is only applicable for the SAP Cloud SDK version of at most 2.19.2. We plan to continuously migrate these blog posts into our List of Tutorials. Feel free to check out our updated Tutorials on the SAP Cloud SDK.



The SAP Cloud SDK makes it easier to transition applications from SAP Cloud Platform Neo to Cloud Foundry because it provides a common set of Cloud Platform abstractions across both environments.

The following blog post will explain how to migrate SAP Cloud SDK based applications from SAP Cloud Platform Neo environment to cloud foundry.

Note: This post is part of a series. For a complete overview, visit the SAP Cloud SDK Overview.

Goal of this blog post


In the tutorial Step 2 with SAP Cloud SDK: HelloWorld on SCP Neo you learned how to create a HelloWorld example on SAP Cloud Platform Neo using the SAP Cloud SDK. In this tutorial, we will make the necessary modification to this HelloWorld application and deploy it to Cloud Foundry.

Note that this approach is recommended only when you are migrating an application from Neo to Cloud Foundry. If you are creating an application only for cloud foundry, follow the tutorial Step 3 with SAP Cloud SDK: HelloWorld on SCP CloudFoundry

Prerequisites



SAP Cloud Foundry Environment – Cloud Foundry Vs Neo


SAP Cloud Platform provides two different development environments: Cloud Foundry and Neo. The availability of different environments provides choices for technologies, runtimes, and services when using SAP Cloud Platform, thereby allowing for great flexibility in your development process.

Cloud Foundry Environment


SAP Cloud Platform Cloud Foundry environment contains the Cloud Foundry Application Runtime, which is based on the open-source application platform managed by the Cloud Foundry Foundation. The Cloud Foundry environment allows you to use multiple programming languages such as Java, Node.js, and community/bring-your-own language options.

Neo Environment


SAP Cloud Platform Neo environment contains SAP propriety runtime. Neo is a feature-rich and easy-to-use development environment, allowing you to develop Java, SAP HANA XS, and HTML5 applications. You can also use SAPUI5 to develop rich user interfaces for modern web-based business applications.

 

To know more about Cloud Foundry and Neo, refer to SAP Cloud Platform Environment – Cloud Foundry Vs Neo

Modify the SAP Cloud SDK based application to deploy to cloud foundry


In Step 2 with SAP Cloud SDK: HelloWorld on SCP Neo we created the SAP Cloud SDK based applications and deployed to Neo environment. To deploy the same application to Cloud Foundry you need to make the following modifications.

Note that you can also move your application to Cloud Foundry if you added further functionality leveraging the SAP Cloud SDK, such as the access to SAP S/4HANA explained in tutorial step 4.
The Cloud Platform abstractions of the SDK will ensure that your source code can mostly remain the same, independent of Neo and Cloud Foundry.

Step 1: Change pom.xml file


The pom.xml file in the application folder is the project management file for Maven where we maintain dependencies and plugins.

This file contains the dependency related to Neo environment. We need to comment those dependencies and add dependencies for Cloud Foundry environment. I will advise you to take a backup of pom.xml file before making any change.

Open this file and comment the entire <properties>, <dependencies>, <build> and <profiles> section. To comment, enclose the code in <!-- .. -->. Instead of commenting it, you may also remove these sections.

Add below dependency and build sections to pom.xml file.
    <dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana.cloudplatform</groupId>
<artifactId>scp-cf</artifactId>
</dependency>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>s4hana-all</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.openejb.maven</groupId>
<artifactId>tomee-maven-plugin</artifactId>
<version>1.7.5</version>
<configuration>
<tomeeClassifier>jaxrs</tomeeClassifier>
<context>ROOT</context>
<libs>
<lib>remove:slf4j-jdk14</lib>
</libs>
</configuration>
</plugin>
</plugins>
</build>

 

The final pom file should look like below.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<name>firstapp - Application</name>
<description>firstapp - Application</description>

<groupId>com.sap.cloud.sdk.tutorial</groupId>
<artifactId>firstapp-application</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<parent>
<groupId>com.sap.cloud.sdk.tutorial</groupId>
<artifactId>firstapp</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana.cloudplatform</groupId>
<artifactId>scp-cf</artifactId>
</dependency>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>s4hana-all</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.openejb.maven</groupId>
<artifactId>tomee-maven-plugin</artifactId>
<version>1.7.5</version>
<configuration>
<tomeeClassifier>jaxrs</tomeeClassifier>
<context>ROOT</context>
<libs>
<lib>remove:slf4j-jdk14</lib>
</libs>
</configuration>
</plugin>
</plugins>
</build>
</project>

Step 2: Modify web.xml file


The web.xml file in src/main/webapp folder contains the deployment descriptor for your web application. This file contains the login and security related configuration which are not valid for cloud foundry. Open this file and comment <login-config>, <session-config>, <security-role> and <security-constraint>. After commenting, the file should look similar to below.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="false">

<!--<login-config>-->
<!--<auth-method>FORM</auth-method>-->
<!--</login-config>-->

<!--<session-config>-->
<!--<session-timeout>20</session-timeout>-->
<!--</session-config>-->

<!--<security-role>-->
<!--<role-name>Everyone</role-name>-->
<!--</security-role>-->

<!--<security-constraint>-->
<!--<web-resource-collection>-->
<!--<web-resource-name>All SAP Cloud Platform users</web-resource-name>-->
<!--<url-pattern>/*</url-pattern>-->
<!--</web-resource-collection>-->
<!--<auth-constraint>-->
<!--<role-name>Everyone</role-name>-->
<!--</auth-constraint>-->

<!--<user-data-constraint>-->
<!--<transport-guarantee>NONE</transport-guarantee>-->
<!--&lt;!&ndash; Use CONFIDENTIAL as transport guarantee to ensure SSL connection (HTTPS) on public deployments-->
<!--<transport-guarantee>CONFIDENTIAL</transport-guarantee> &ndash;&gt;-->
<!--</user-data-constraint>-->
<!--</security-constraint>-->

<filter>
<filter-name>RestCsrfPreventionFilter</filter-name>
<filter-class>org.apache.catalina.filters.RestCsrfPreventionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RestCsrfPreventionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
<filter-name>HttpSecurityHeadersFilter</filter-name>
<filter-class>com.sap.cloud.sdk.cloudplatform.security.servlet.HttpSecurityHeadersFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpSecurityHeadersFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
<filter-name>HttpCachingHeaderFilter</filter-name>
<filter-class>com.sap.cloud.sdk.cloudplatform.security.servlet.HttpCachingHeaderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpCachingHeaderFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

 

Step 3: Add manifest.yml file


manifest.yml is the deployment descriptor for CloudFoundry application. Create a new file in the root folder with name manifest.yml and add below code.
---
applications:

- name: firstapp
memory: 768M
random-route: true
path: application/target/firstapp-application.war
buildpack: sap_java_buildpack
env:
TARGET_RUNTIME: tomee
JBP_CONFIG_SAPJVM_MEMORY_SIZES: 'metaspace:96m..'

 

Note: You may have to change the name and path if you have chosen different artifact id. You may also have to increase the memory if your application does more than the plain HelloWorld example.

Deploy to Cloud Foundry


We have made all the necessary modification and the project is ready to be deployed to cloud foundry. Open your command line or terminal in IntelliJ IDEA. Change into the firstapp directory, the root directory of your project and run the following command:
cd /path/to/firstapp

mvn clean package

 

This tells maven to remove any files from previous assemblies (clean) and to assemble our project (package). After running the command there should be a directory target inside of the application directory, containing a file called firstapp-application.war. This is the file that we will deploy to Cloud Foundry.

Now you can deploy the application by entering the following command:
cf push

 

After the deployment is finished, cf CLI’s output should look like this:



 

Visit the application under its corresponding URL as it is shown in the output above.



That’s it. We have successfully migrated our application from SAP Cloud Platform Neo environment to Cloud Foundry environment without adapting any source code. Thanks to SAP Cloud SDK.

Check out step 3 for further information about running the Cloud Foundry application locally.

 

You can now continue with Step 4 with SAP Cloud SDK: Calling an OData Service with the Virtual Data Model

 

Appendix


If you want to secure your application on Cloud Foundry as explained in Step 7 with SAP Cloud SDK: Secure your Application on SAP Cloud Platform, CloudFoundry, you need to add Spring security files as well.

Security configuration related to Cloud Foundry environment is specified in Spring Security Configuration file(spring-security.xml) and application.properties file. We need to create these 2 files.



 

As shown in the above image, create a new file in WEB-INF folder with name spring-security.xml and paste below code. 
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

<sec:http pattern="/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
authentication-manager-ref="authenticationManager"
use-expressions="true">
<sec:anonymous enabled="false" />

<!-- Example: Check a specific OAuth Scope (i.e., authorization) on a resource -->
<!--<sec:intercept-url pattern="/hello" access="#oauth2.hasScope('${xs.appname}.Display')" method="GET" />-->

<!-- Example: Check only authentication on a resource -->

<sec:intercept-url pattern="/**" access="isAuthenticated()" method="GET" />

<sec:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
</sec:http>

<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
</bean>

<bean id="oauthWebExpressionHandler"
class="org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler">
</bean>

<bean id="accessDecisionManager"
class="org.springframework.security.access.vote.UnanimousBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler" ref="oauthWebExpressionHandler" />
</bean>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>

<sec:authentication-manager alias="authenticationManager"/>

<oauth:resource-server id="resourceServerFilter"
resource-id="springsec" token-services-ref="offlineTokenServices" />

<bean id="offlineTokenServices"
class="com.sap.xs2.security.commons.SAPOfflineTokenServices">
<property name="verificationKey" value="${xs.uaa.verificationkey}" />
<property name="trustedClientId" value="${xs.uaa.clientid}" />
<property name="trustedIdentityZone" value="${xs.uaa.identityzone}" />
</bean>

<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

<!-- define properties file =========================================================== -->
<bean class="com.sap.xs2.security.commons.SAPPropertyPlaceholderConfigurer">
<property name="location" value="classpath:/application.properties" />
</bean>
</beans>

 

Create another file in resources folder with name application.properties and paste below code.
# parameters for local testing
xs.appname=firstapp

 

Note: You may have to change "firstapp" as per your artifact id.