Skip to Content
Technical Articles

Migrate SAP Cloud SDK Based Applications from SAP Cloud Platform Neo Environment to Cloud Foundry

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.

Be the first to leave a comment
You must be Logged on to comment or reply to a post.