Exercise: Building a CRUD Extension using Java

Objectives
After completing this lesson, you will be able to:

After completing this lesson, you will be able to:

  • Using the Java language and the Spring framework, build an extension application executing CRUD operations on data in SAP S/4HANA Cloud

Building a CRUD Extension Application using Java and the Spring Framework

Description

Create the Address Manager application using the Spring framework. Run it connected to the SAP API Business Hub sandbox, connect it to an SAP S/4HANA Cloud system, deploy it to Cloud Foundry, and then finally create a Destination service and use it to connect the application to the back-end.

Prerequisites

For the complete execution of current exercise, you must prior execute the following other exercises:

  • Create your Free Trial Account in SAP BTP
  • Activating the APIs in SAP S/4HANA Cloud: this exercise activates the required API in the S/4HANA Cloud tenant.

For the full execution of this exercise, you need to have the following software installed on your laptop:

SoftwareType
Apache Mavenapplication
Cloud Foundry CLIapplication
Java Development Kit, Standard Edition, version 8application
IntelliJ IDEA Community Editionapplication
Visual Studio Codeapplication
Cloudfoundry Manifest YML SupportVisual Studio Code Extension
Debugger for JavaVisual Studio Code Extension
Project Manager for JavaVisual Studio Code Extension
Java Extension PackVisual Studio Code Extension
Java Test RunnerVisual Studio Code Extension
Language Support for Java(TM) by Red HatVisual Studio Code Extension

Some steps of this exercise depend on the https://api.sap.com website. As a consequence, they may not run properly if the website is not running 100% correctly. In this case, proceed with the exercise to reach the part that runs against the SAP S/4HANA Cloud instance.

Information for execution

The exercise comes with an archive file:

java-adman-spring-solution.zip[download] contains the Maven project in its final status after the correct execution of the exercise. This project can be used to clarify the correct solution or to copy and paste parts of the source code.

In the case you wish to run the solution application directly without going through the exercise steps, then complete the following actions (this is not a prerequisite to exercise execution):

  1. Extract the archive to a folder in your local system.
  2. Open the Windows Powershell and change the directory to the project root folder.
  3. Execute the following sequence of commands (replace ">>>YOUR API KEY<<<" with your own API Key, for example, "FDqbnElM7mgmgqbIKBFHRpS1dvpt6sHD". To get your API Key, open https://api.sap.com/api/API_BUSINESS_PARTNER, then log on, and choose Show API Key).
    Code snippet
    $env:S4_APIKEY=">>>YOUR API KEY<<<"
    $env:S4_URL="https://sandbox.api.sap.com/s4hanacloud"
    mvn clean install
    cd application
    mvn spring-boot:run
    Copy code
  4. Wait until the Tomcat server starts. Open the application at http://localhost:8080/address-manager.

To configure the application, complete the following exercise steps.

The application reads the following environment variables, such variables need to be properly set for the application to interact with the back-end service:

VariableContent
S4_DESTINATIONThe name of the destination defined within the Destination service of Cloud Foundry. Use it when running in Cloud Foundry.
S4_URLThe URL of the backend ERP system. Use it when running locally.
S4_USERNAMEThe user name to access the backend ERP system. Use it when running locally.
S4_PASSWORDThe user name to access the backend ERP system. Use it when running locally.
S4_APIKEYYour API Key identifier, required to access the SAP API Business Hub. You can get your apikey at https://api.sap.com.

Two authentication methods are possible. Based on the method, you will provide the corresponding environment variables:

  • Basic user and password authentication: used by the S/4HANA Cloud system.
  • No Authentication plus API key: used by the SAP API Business Hub Sandbox system.

Task 1: Creating the Spring Boot Development Project in a Local IDE (Visual Studio Code or IntelliJ IDEA)

Steps

  1. In a local folder (folder D:\workspace if you are in the SAP Training System), generate an extension application project from an archetype, using the following information: [play]

    ParameterValue
    Project folderD:\workspace\java-adman-spring
    archetypeGroupIdcom.sap.cloud.sdk.archetypes
    archetypeArtifactIdscp-cf-spring
    archetypeVersion3.62.0 (you may use RELEASE, to get the latest version)
    groupIdcom.example
    artifactIdjava-adman-spring
    version1.0-SNAPSHOT
    1. Open the Windows PowerShell, and execute the following command:

      cd D:\workspace.

    2. Execute the following command (you can copy it from the java-adman-spring-1-create-project.txt file [download]):

      Code snippet
      mvn archetype:generate "-DarchetypeGroupId=com.sap.cloud.sdk.archetypes" "-DarchetypeArtifactId=scp-cf-spring" "-DarchetypeVersion=3.62.0" "-DgroupId=com.example" "-DartifactId=java-adman-spring" "-Dversion=1.0-SNAPSHOT"
      Copy code
    3. Wait until the project is generated. When requested, enter Y to continue.

      If successful, the BUILD SUCCESS message displays.
  2. Build and run the application from the command line. [play]

    1. In the Windows PowerShell, run the following commands:

      Code snippet
      cd D:\workspace\java-adman-spring
      mvn clean install -U
      Copy code
      Wait until the application is built successfully.

    2. In the Windows PowerShell, run the following commands:

      Code snippet
      cd application
      mvn spring-boot:run
      Copy code
      Wait until the Tomcat server starts.

    3. In your Web browser (for example, Google Chrome), open http://localhost:8080.

    4. In the PowerShell, choose Ctrl+C and then Y and stop the Tomcat server.

  3. Open the local project folder using your preferred local Java IDE (such as, Visual Studio Code). [play]

    1. Open Windows File Explorer and navigate to the project folder. Right-click and execute Open with Code (in case you use IntelliJ IDEA: Open Folder as IntelliJ IDEA Community Edition Project, in case you are asked, specify it is a Maven project).

    2. Check the status bar of your Java IDE (lower right corner of the window) until the analysis (build) of the project is complete.

  4. Review the project content. [play]

    1. Open application/src/main/java/com/example/ and review the project files in the sub-folders.

      The HelloWorldController listens in the context of /hello for incoming HTTP requests. When a GET request is sent to this resource, it logs the string 'I am running' and returns a response based on the HelloWorldResponse class. As expected in Spring programming, the Model-View-Controller pattern is applied, so the controller object is separated from the model one.

    2. Open the application/src/main/resources/static/index.html file and review the code.

      The index file that we see here helps us to validate a fresh deployment of our app. It welcomes every visitor who sends a request to our application base URL with a generic landing page.

    3. Open the application/src/test/java/com/example/UnitTest.java file and review the code.

      We use the unit-tests module for tests that ensure the functional correctness of small functional units of our application, typically on Java API level.

    4. Open the integration-tests/src/test/java/com/example/HelloWorldControllerTest.java file and review the code.

      The integration test module holds tests that typically test multiple parts of the application and their interplay. These tests are often written on the level of HTTP requests and expected responses.

    5. Open the manifest.yml file and review the code.

      The manifest.yml file is used to tell the Cloud foundry environment which resources our application needs to run. This is interpreted by Cloud Foundry when deploying the application. The following figure shows, for example, the memory requirements, environment variable definitions, and instances of platform services that should be bound to our app.

  5. In your IDE (for example, Visual Studio Code), run the application in debug mode. Set a breakpoint in file HelloWorldController.java at line 26. Open the application in the browser and verify that the execution stops at the breakpoint. Continue the execution to the end. Remove the breakpoint. Stop the application. [play]

    1. Open the application/src/main/java/com/example/Application.java file.

    2. If you are using Visual Studio Code, choose the small Debug command that appears just before the Main() method definition.

      It may take a couple of minutes to display until the application build is automatically executed in background.

    3. If you are using IntelliJ IDEA, select the little green arrow on the left side of the class definition and choose Debug Application.Main(). A run configuration is automatically created and the application is started.

    4. Open the application/src/main/java/com/example/controllers/HelloWorldController.java file. Create a breakpoint by selecting aside line number 26. A red dot appears beside the number.

    5. Open the Web browser at http://localhost:8080. The welcome screen appears.

    6. In the welcome screen, choose HelloWorldController . The controller runs and the execution stops in the debugger at the breakpoint.

    7. In the Debugger, choose Continue (or Resume Program). hello: 'world' appears in the browser.

    8. In the HelloWorldController.java, click on the red dot to remove the breakpoint.

    9. Choose Stop (or Stop 'Application').

  6. Deploy the application to Cloud Foundry.

    1. Open the Windows PowerShell. In required, you can open the Cloud Foundry CLI by executing the following commands:

      Code snippet
      cf login
      Copy code
      Enter your SAP BTP API endpoint, e-mail, and password.

    2. In the Windows PowerShell, run the following commands:

      Code snippet
      cd D:\workspace\java-adman-spring
      cf push
      Copy code
      At the end of the deployment process, you will get a text such as the following:
      Code snippet
           state     since                  cpu     memory         disk           details
      #0   running   2020-04-24T17:25:03Z   66.4%   167.5M of 1G   152.4M of 1G
      Copy code

  7. Look for the running application in the SAP BTP Cockpit and open it.

    1. In Google Chrome, open the URL https://account.hanatrial.ondemand.com. If required, enter your e-mail and password.

    2. In the SAP BTP Cockpit, choose Enter Your Trial account. Navigate to your trial Subaccount. Navigate to the dev space.

    3. Choose the java-adman-spring application name.

    4. Choose the Application Route. The application opens in the Welcome page.

  8. Create a debug configuration to attach the remote Java application in Cloud Foundry.

    1. If you are using Visual Studio Code, choose RunAdd ConfigurationJava. The launch.json file is opened.

    2. In the launch.json file, add the following debug configuration (for simplicity, you can just copy the whole content of file java-adman-spring-2-launch-json.txt file [download]):

      Code snippet
      {
       "type": "java",
       "name": "Attach Application",
       "request": "attach", 
       "hostName": "localhost",
       "port": 5005,
       "sourcePaths": [ "${workspaceFolder}" ] 
      } 
      
      Copy code
  9. If you are using IntelliJ IDEA, create a debug configuration to attach the remote Java application in Cloud Foundry.

    1. In IntelliJ IDEA, choose RunEdit Configurations...

    2. You should find a configuration with name Application. Rename it to Launch Application

    3. In the Run/Debug Configurations window, choose Add New ConfigurationRemote JVM Debug. Enter the following information:

      FieldValue
      NameAttach Application
      Debugger modeAttach to remote JVM
      Hostlocalhost
      Port5005
      User module classpathjava-adman-spring
    4. Choose Ok.

  10. Attach the debugger of your local IDE (for example, Visual Studio Code) to the remote application running in Cloud Foundry.

    1. In the PowerShell, make sure that the current directory is the project root folder D:\workspace\java-adman-spring.

    2. To enable the remote application for debug, execute the following commands (you can find them in the java-adman-spring_enable_cf_debug.txt file [download]):

      Code snippet
      cf set-env java-adman-spring JBP_CONFIG_JAVA_OPTS "[java_opts: '-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n']"
      cf enable-ssh java-adman-spring
      cf restage java-adman-spring
      cf ssh -N -T -L 5005:localhost:8000 java-adman-spring
      Copy code
    3. In the local IDE (for example Visual Studio Code) run the Attach Application configuration in debug mode. The debugger attaches to the remote application.

  11. In your IDE (for example, Visual Studio Code), set a breakpoint in the HelloWorldController.java file at line 26. Open the application in the browser and verify that the execution stops at the breakpoint. Continue the execution to the end. Remove the breakpoint. Stop the application.

    1. Open the application/src/main/java/com/example/controllers/HelloWorldController.java file. Create a breakpoint clicking aside the line number 26. A red dot appears aside the number.

    2. Open the Web browser in the SAP BTP Cockpit at the welcome page of the java-adman-spring application that you just deployed.

    3. In the welcome screen, choose HelloWorldController. The controller runs and the execution stops in the debugger at the breakpoint.

    4. In the Debugger, choose Continue (or Resume Program). hello: 'world' appears in the browser.

    5. In the HelloWorldController.java, click on the red dot to remove the breakpoint.

    6. Disconnect the debugger.

    7. In the Powershell, chooseCtrl+C to interrupt the cf ssh command.

Task 2: Creating the Spring Boot Development Project in the SAP Business Application Studio

Steps

  1. Open the SAP Business Application Studiotraining development space.

    1. In your Web browser (for example, Google Chrome), open https://account.hanatrial.ondemand.com. If requested, enter your user and password.

    2. Choose SAP Business Application Studio.

    3. Enter the training development space.

  2. In the projects folder, generate an extension application project from an archetype, using the following information:

    ParameterValue
    archetypeGroupIdcom.sap.cloud.sdk.archetypes
    archetypeArtifactIdscp-cf-spring
    archetypeVersion3.62.0 (you may use RELEASE, to get the latest version)
    groupIdcom.example
    artifactIdjava-adman-spring
    version1.0-SNAPSHOT
    1. Choose FileOpen Workspace... (Ctrl+Alt+W), choose the projects folder and choose Open.

    2. Choose TerminalNew Terminal. A terminal window appears in the lower part of the screen.

    3. In the terminal, execute the following command (you can copy it from the java-adman-spring-1-create-project.txt file [download]):

      Code snippet
      mvn archetype:generate "-DarchetypeGroupId=com.sap.cloud.sdk.archetypes" "-DarchetypeArtifactId=scp-cf-spring" "-DarchetypeVersion=3.62.0" "-DgroupId=com.example" "-DartifactId=java-adman-spring" "-Dversion=1.0-SNAPSHOT"
      Copy code
    4. Wait until the project is generated. If requested, enter Y to continue.

      If successful, a BUILD SUCCESS message displays.
  3. Open the projects/java-adman-spring folder as a workspace.

    1. Choose FileOpen Workspace... (Ctrl+Alt+W), choose the projects/java-adman-spring folder and choose Open.

  4. Build and run the application from the command line.

    1. Choose TerminalNew Terminal. A terminal window appears in the lower part of the screen.

    2. In the terminal, execute the following command:

      Code snippet
      mvn clean install -U
      Copy code
      Wait until the application is built successfully.

    3. In the terminal, execute the following commands:

      Code snippet
      cd application
      mvn spring-boot:run
      Copy code
      Wait until the Tomcat server starts. After a few seconds a pop-up window appears with the following message: A service is listening to port 8080. Choose Expose and Open, then press enter. The application is opened.

    4. Return to the terminal, choose Ctrl+C to stop the Tomcat server.

  5. Review the project content.

    1. Open application/src/main/java/com/example/ and review the project files in the sub-folders.

      The HelloWorldController listens in the context of /hello for incoming HTTP requests. When a GET request is sent to this resource, it logs the string 'I am running' and returns a response based on the HelloWorldResponse class. As expected in Spring programming, the Model-View-Controller pattern is applied, so the controller object is separated from the model one.

    2. Open the application/src/main/resources/static/index.html file and review the code.

      The index file that we see here helps us to validate a fresh deployment of our app. It welcomes every visitor who sends a request to our application base URL with a generic landing page.

    3. Open the application/src/test/java/com/example/UnitTest.java file and review the code.

      We use the unit-tests module for tests that ensure the functional correctness of small functional units of our application, typically on Java API level.

    4. Open the integration-tests/src/test/java/com/example/HelloWorldControllerTest.java file and review the code.

      The integration test module holds tests that typically test multiple parts of the application and their interplay. These tests are often written on the level of HTTP requests and expected responses.

    5. Open the manifest.yml file and review the code.

      The manifest.yml file is used to tell the Cloud foundry environment which resources our application needs to run. This is interpreted by Cloud Foundry when deploying the application. The following figure shows an example of the memory requirements, environment variable definitions, and instances of platform services that should be bound to our app.

  6. Run the application in debug mode. Set a breakpoint in the HelloWorldController.java file at line 26. Open the application in the browser and verify that the execution stops at the breakpoint. Continue the execution to the end. Remove the breakpoint. Stop the application.

    1. Open the application/src/main/java/com/example/Application.java file.

    2. Choose the small Debug command that appears just before the Main() method definition.

    3. Once the application has started, a pop up window appears stating A service is listening to port 8080. Choose Open in New Tab. A new tab is opened showing the application welcome screen.

    4. Open the application/src/main/java/com/example/controllers/HelloWorldController.java file. Create a breakpoint by selecting aside line number 26. A red dot appears beside the number.

    5. In the welcome screen, choose HelloWorldController. The controller runs and the execution stops in the debugger at the breakpoint.

    6. In the Debugger, choose Continue(in the Debug page). hello: "world" appears in the application page.

    7. In the HelloWorldController.java, click on the red dot to remove the breakpoint.

    8. Choose Stop.

  7. Deploy the application to Cloud Foundry.

    1. Choose TerminalNew Terminal. A terminal window appears in the lower part of the screen.

    2. If required, login to the Cloud Foundry CLI by executing the following commands

      Code snippet
      cf login
      
      Copy code
      Enter your SAP BTP API endpoint, e-mail and password.

    3. In the terminal, make sure you are in the project root folder, then run the following command:

      Code snippet
      cf push
      Copy code
      At the end of the deployment process, you will get a text, such as the following:
      Code snippet
           state     since                  cpu     memory         disk           details
      #0   running   2020-04-24T17:25:03Z   66.4%   167.5M of 1G   152.4M of 1G
      Copy code

  8. Look for the running application in the SAP BTP Cockpit and open it.

    1. In Google Chrome, open the URL https://account.hanatrial.ondemand.com. If required, enter your e-mail and password.

    2. In the SAP BTP Cockpit, choose Enter Your Trial account. Navigate to your trial Subaccount. Navigate to the dev space.

    3. Choose the java-adman-spring application name.

    4. Choose the Application Route. The application opens in the Welcome page.

  9. In SAP Business Application Studio, create a debug configuration to attach the remote Java application in Cloud Foundry.

    1. Choose RunOpen Configurations. The launch.json file is opened.

    2. In the launch.json file, change the name of the existing configuration to Launch Application, then add the following debug configuration (for simplicity, you can just copy the whole content of file java-adman-spring-2-launch-json.txt file [download]):

      Code snippet
      {
       "type": "java",
       "name": "Attach Application",
       "request": "attach", 
       "hostName": "localhost",
       "port": 5005,
       "sourcePaths": [ "${workspaceFolder}" ] 
      } 
      
      Copy code
  10. Attach the debugger of SAP Business Application Studio to the remote application running in Cloud Foundry.

    1. Open a terminal, make sure that the current directory is the project root folder.

    2. To enable the remote application for debug, execute the following commands (you can find them in the java-adman-spring_enable_cf_debug.txt file [download]):

      Code snippet
      cf set-env java-adman-spring JBP_CONFIG_JAVA_OPTS "[java_opts: '-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n']"
      cf enable-ssh java-adman-spring
      cf restage java-adman-spring
      cf ssh -N -T -L 5005:localhost:8000 java-adman-spring
      Copy code
      Ignore eventual messages proposing you to expose port 5005.

    3. In SAP Business Application Studio, in the Debug tab, run the Attach Application configuration. The debugger attaches to the remote application.

  11. Set a breakpoint in the HelloWorldController.java file at line 26. Open the application in the browser and verify that the execution stops at the breakpoint. Continue the execution to the end. Remove the breakpoint. Stop the application.

    1. Open the application/src/main/java/com/example/controllers/HelloWorldController.java file. Create a breakpoint by selecting aside line number 26. A red dot appears beside the number.

    2. Open the Web browser in the SAP BTP Cockpit at the welcome page of the java-adman-spring application you just deployed.

    3. In the welcome screen, choose HelloWorldController. The controller runs and the execution stops in the debugger, at the breakpoint (switch back to SAP Business Application Studio).

    4. In the Debugger, choose Continue. hello: 'world' appears in the browser.

    5. In the HelloWorldController.java, click on the red dot to remove the breakpoint.

    6. Stop the debugger.

    7. In the Terminal, chooseCtrl+C to interrupt the cf ssh command.

Task 3: Create the Address Manager Application using SAP Business Application Studio

Steps

  1. At the top of the initial application, create an Address Manager application that maintains the SAP S/4HANA Cloud business partners address information. The application is provided in the exercise files, and includes the following parts:

    PartFileDescription
    Java back-endjava-adman-spring-backend.zip[download]Based on SAP Cloud SDK. Realizes two rest services "/api/business-partners" and "/api/addresses".
    SAPUI5 front-endjava-adman-spring-frontend.zip[download]A JavaScript frontend based on the SAPUI5 library. It will run in the web browser.
    1. Navigate to the java-adman-spring\application\src\main\java\com\example folder.

    2. Right-click on the example folder, choose Upload Files..., upload the java-adman-spring-backend.zip archive [download].

    3. Right-click on the example folder, choose Open in Terminal.

    4. In the terminal, execute the following commands:

      Code snippet
      unzip *.zip
      rm *.zip
      Copy code
    5. Close the terminal.

    6. Navigate to the java-adman-spring\application\src\main\resources\static folder.

    7. Right-click on the static folder, choose Upload Files..., upload the java-adman-spring-frontend.zip archive [download].

    8. Right-click on the static folder, choose Open in Terminal.

    9. In the terminal execute the following commands:

      Code snippet
      unzip *.zip
      rm *.zip
      Copy code
    10. Close the terminal.

      Note
      If anything is unclear, you can compare your project with the one provided within the java-adman-spring-solution.zip file [download].
    11. Review the service definitions in application/src/main/java/com/example/adman.

      The content of BackendConnector.java is as follows:

      Code snippet
      package com.example.adman;
      
      import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultDestination;
      import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor;
      import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination;
      
      public class BackendConnector {
          private static String destinationName;
          private static String system_uri;
          private static String username;
          private static String password;
          private static String authentication;
          private static String apikey;
          private static HttpDestination destination;
      
          static {
              // Get the environment variables
              destinationName = System.getenv("S4_DESTINATION");
              system_uri = System.getenv("S4_URL");
              username = System.getenv("S4_USERNAME");
              password = System.getenv("S4_PASSWORD");
              authentication = (username != null && password != null) ?
                      "BasicAuthentication" : "NoAuthentication";
              apikey = System.getenv("S4_APIKEY");
              if (apikey==null) apikey="";
      
              if (destinationName != null){
                  // Get the destination via the Destination service
                  // of Cloud Foundry, in the SCP.
                  destination = DestinationAccessor
                          .getDestination(destinationName).asHttp();
              }
              else {
                  // Create the destination at run time,
                  // using the URI and credentials
                  // provided in the environment variables.
                  destination = DefaultDestination.builder()
                          .property("Name", "DESTINATION")
                          .property("URL", system_uri)
                          .property("Type", "HTTP")
                          .property("Authentication", authentication)
                          .property("User", username)
                          .property("Password", password)
                          .build().asHttp();
              }
          }
      
          public static HttpDestination getDestination() {
              return destination;
          }
          public static String getApikey() {
              return apikey;
          }
      }
      Copy code
      The content of BusinessPartnerController.java is as follows:
      Code snippet
      package com.example.adman;
      
      import com.google.gson.Gson;
      import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.businesspartner.BusinessPartner;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.http.HttpHeaders;
      import org.springframework.http.HttpStatus;
      import org.springframework.http.MediaType;
      import org.springframework.http.ResponseEntity;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      import org.springframework.web.server.ResponseStatusException;
      
      import java.util.List;
      
      @RestController
      public class BusinessPartnerController {
      
          private static final Logger logger =
                  LoggerFactory.getLogger(BusinessPartnerController.class);
      
          @GetMapping( "/api/business-partners" )
          ResponseEntity<String> doGet(
                  @RequestParam(required = false) String id)  {
      
              String jsonResult;
              if (id == null) {
                  // Get all Business Partners
                  List<BusinessPartner> list;
                  try {
                      list = BusinessPartnerRepository.findAll();
                  }
                  catch (BusinessPartnerRepository_InternalErrorException e)
                  {
                      final String message = "Internal error " +
                              "retrieving business partners.";
                      logger.error(message, e);
                      throw new ResponseStatusException(
                              HttpStatus.INTERNAL_SERVER_ERROR, message, e);
                  }
      
                  // Convert to JSon and remove null values
                  jsonResult = new Gson().toJson(list);
              }
              else {
                  // Get Business Partner based on id
                  BusinessPartner bp;
                  try {
                      bp = BusinessPartnerRepository.findById(id);
                  }
                  catch (BusinessPartnerRepository_InternalErrorException e)
                  {
                      final String message
                              = "Internal error retrieving " +
                              "business partner " + id;
                      logger.error(message, e);
                      throw new ResponseStatusException(
                              HttpStatus.INTERNAL_SERVER_ERROR, message, e);
                  }
      
                  // Convert to JSon and remove null values
                  jsonResult = new Gson().toJson(bp);
              }
      
              // Prepare response headers (optional)
              HttpHeaders headers = new HttpHeaders();
              headers.setContentType(MediaType.APPLICATION_JSON);
      
              return new ResponseEntity<>(
                      jsonResult, headers, HttpStatus.OK);
          }
      }
      Copy code
      The content of BusinessPartnerRepository.java is as follows:
      Code snippet
      package com.example.adman;
      
      import com.sap.cloud.sdk.datamodel.odata.client.exception.ODataResponseException;
      import com.sap.cloud.sdk.datamodel.odata.helper.Order;
      import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.businesspartner.BusinessPartner;
      import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.businesspartner.BusinessPartnerAddress;
      import com.sap.cloud.sdk.s4hana.datamodel.odata.services.DefaultBusinessPartnerService;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      import java.util.List;
      
      public class BusinessPartnerRepository {
      
          private static final String CATEGORY_PERSON = "1";
          private static final Logger logger =
                  LoggerFactory.getLogger(BusinessPartnerRepository.class);
      
          public static BusinessPartner findById(String id) {
      
              BusinessPartner result;
              try {
                  result = new DefaultBusinessPartnerService()
                          .getBusinessPartnerByKey(id)
                          .select(BusinessPartner.BUSINESS_PARTNER,
                              BusinessPartner.LAST_NAME,
                              BusinessPartner.FIRST_NAME,
                              BusinessPartner.IS_MALE,
                              BusinessPartner.IS_FEMALE,
                              BusinessPartner.CREATION_DATE,
                              BusinessPartner.TO_BUSINESS_PARTNER_ADDRESS
                                      .select(
                                  BusinessPartnerAddress.BUSINESS_PARTNER,
                                  BusinessPartnerAddress.ADDRESS_ID,
                                  BusinessPartnerAddress.COUNTRY,
                                  BusinessPartnerAddress.POSTAL_CODE,
                                  BusinessPartnerAddress.CITY_NAME,
                                  BusinessPartnerAddress.STREET_NAME,
                                  BusinessPartnerAddress.HOUSE_NUMBER))
                      .withHeader("apikey", BackendConnector.getApikey())
                          .executeRequest(BackendConnector.getDestination());
              } catch (ODataResponseException e) {
                  final String message = "OData error retrieving " +
                          "business partner " + id;
                  logger.error(message, e);
                  throw new BusinessPartnerRepository_InternalErrorException(
                          message, e);
              }
              return result;
          }
      
          public static List<BusinessPartner> findAll() {
      
              List<BusinessPartner> result;
              try {
                  result = new DefaultBusinessPartnerService()
                          .getAllBusinessPartner()
                          .select(BusinessPartner.BUSINESS_PARTNER,
                                  BusinessPartner.LAST_NAME,
                                  BusinessPartner.FIRST_NAME)
                          .filter(BusinessPartner.BUSINESS_PARTNER_CATEGORY
                                  .eq(CATEGORY_PERSON))
                          .orderBy(BusinessPartner.LAST_NAME, Order.ASC)
                          .withHeader("apikey", BackendConnector.getApikey())
                          .executeRequest(BackendConnector.getDestination());
              }
              catch (ODataResponseException e) {
                  final String message = "OData error " +
                          "retrieving business partners.";
                  logger.error(message, e);
                  throw new BusinessPartnerRepository_InternalErrorException(
                          message, e);
              }
              return result;
          }
      }
      Copy code
      The content of BusinessPartnerRepository_InternalErrorException.java is as follows:
      Code snippet
      package com.example.adman;
      
      public class BusinessPartnerRepository_InternalErrorException
              extends RuntimeException {
      
          BusinessPartnerRepository_InternalErrorException(
                  String message, Throwable cause){
              super(message, cause);
          }
      }
      Copy code
      The content of BusinessPartnerAddressController.java is as follows:
      Code snippet
      package com.example.adman;
      
      import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.businesspartner.BusinessPartnerAddress;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.http.HttpStatus;
      import org.springframework.web.bind.annotation.*;
      import org.springframework.web.server.ResponseStatusException;
      
      @RestController
      public class BusinessPartnerAddressController {
      
          private static final Logger logger
                  = LoggerFactory.getLogger(BusinessPartnerController.class);
      
          @PostMapping("/api/addresses")
          BusinessPartnerAddress doPost(
                  @RequestBody BusinessPartnerAddress newAddress) {
      
              BusinessPartnerAddress bpa;
              try {
                  bpa = BusinessPartnerAddressRepository.save(newAddress);
              }
              catch (
                  BusinessPartnerAddressRepository_InternalErrorException e)
              {
                  final String message = "Internal error " +
                          "saving the business partner address.";
                  logger.error(message, e);
                  throw new ResponseStatusException(
                          HttpStatus.INTERNAL_SERVER_ERROR, message, e);
              }
              return bpa;
          }
      
          @PatchMapping("/api/addresses")
          BusinessPartnerAddress doPatch(
                  @RequestBody BusinessPartnerAddress address) {
      
              BusinessPartnerAddress bpa;
              try {
                  bpa = BusinessPartnerAddressRepository.save(address);
              }
              catch (
                  BusinessPartnerAddressRepository_InternalErrorException e)
              {
                  final String message = "Internal error " +
                          "updating the business partner address.";
                  logger.error(message, e);
                  throw new ResponseStatusException(
                          HttpStatus.INTERNAL_SERVER_ERROR, message, e);
              }
              return bpa;
          }
      
          @DeleteMapping("/api/addresses")
          protected void doDelete(
                  @RequestParam String businessPartnerId,
                  @RequestParam String addressId) {
              try {
                  BusinessPartnerAddressRepository
                          .delete(businessPartnerId, addressId);
              }
              catch (
                  BusinessPartnerAddressRepository_InternalErrorException e)
              {
                  final String message = "Internal error " +
                          "deleting the business partner address.";
                  logger.error(message, e);
                  throw new ResponseStatusException(
                          HttpStatus.INTERNAL_SERVER_ERROR, message, e);
              }
          }
      }
      Copy code
      The content of BusinessPartnerAddressRepository.java is as follows:
      Code snippet
      package com.example.adman;
      
      import com.sap.cloud.sdk.datamodel.odata.client.exception.ODataResponseException;
      import com.sap.cloud.sdk.datamodel.odata.helper.ModificationResponse;
      import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.businesspartner.BusinessPartnerAddress;
      import com.sap.cloud.sdk.s4hana.datamodel.odata.services.DefaultBusinessPartnerService;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      public class BusinessPartnerAddressRepository {
      
          private static final Logger logger =
                  LoggerFactory.getLogger(BusinessPartnerAddressRepository.class);
      
          public static BusinessPartnerAddress save(
                  BusinessPartnerAddress address) {
      
              ModificationResponse<BusinessPartnerAddress> response;
              if(address.getAddressID()==null) {
                  // Create new address
                  try {
                      response = new DefaultBusinessPartnerService()
                              .createBusinessPartnerAddress(address)
                              .withHeader("apikey",
                                      BackendConnector.getApikey())
                              .executeRequest(BackendConnector.getDestination());
      
                  } catch (ODataResponseException e) {
                      final String message = "OData error " +
                              "creating new business partner address.";
                      logger.error(message, e);
                      throw new BusinessPartnerAddressRepository_InternalErrorException(
                              message, e);
                  }
              }
              else {
                  // Update existing address
                  try {
                      final BusinessPartnerAddress addressToUpdate =
                              createAddressToUpdate(address);
                      response = new DefaultBusinessPartnerService()
                              .updateBusinessPartnerAddress(addressToUpdate)
                              .withHeader("apikey",
                                      BackendConnector.getApikey())
                              .executeRequest(BackendConnector.getDestination());
      
                  } catch (ODataResponseException e) {
                      final String message = "OData error " +
                              "updating business partner address.";
                      logger.error(message, e);
                      throw new BusinessPartnerAddressRepository_InternalErrorException(
                              message, e);
                  }
              }
              return response.getModifiedEntity();
          }
      
          private static BusinessPartnerAddress createAddressToUpdate(
                  BusinessPartnerAddress addressFromBody) {
      
              final BusinessPartnerAddress addressToUpdate =
                      BusinessPartnerAddress.builder()
                      .businessPartner(addressFromBody.getBusinessPartner())
                      .addressID(addressFromBody.getAddressID())
                      .build();
      
              addressToUpdate.setStreetName(addressFromBody.getStreetName());
              addressToUpdate.setHouseNumber(addressFromBody.getHouseNumber());
              addressToUpdate.setCityName(addressFromBody.getCityName());
              addressToUpdate.setPostalCode(addressFromBody.getPostalCode());
              addressToUpdate.setCountry(addressFromBody.getCountry());
              return addressToUpdate;
          }
      
          static void delete(
                  String businessPartnerId, String addressId) {
      
              final BusinessPartnerAddress addressToDelete =
                      BusinessPartnerAddress.builder()
                      .businessPartner(businessPartnerId)
                      .addressID(addressId)
                      .build();
      
              try {
                  new DefaultBusinessPartnerService()
                          .deleteBusinessPartnerAddress(addressToDelete)
                          .withHeader("apikey",
                                  BackendConnector.getApikey())
                          .executeRequest(BackendConnector.getDestination());
      
              } catch (ODataResponseException e) {
                  final String message = "OData error " +
                          "deleting business partner address.";
                  logger.error(message, e);
                  throw new BusinessPartnerAddressRepository_InternalErrorException(
                          message, e);
              }
          }
      }
      Copy code
      The content of BusinessPartnerAddressRepository_InternalErrorException.java is as follows:
      Code snippet
      package com.example.adman;
      
      public class BusinessPartnerAddressRepository_InternalErrorException 
              extends RuntimeException {
      
          BusinessPartnerAddressRepository_InternalErrorException(
                  String message, Throwable cause){
              super(message, cause);
          }
      }
      Copy code

  2. In SAP Business Application Studio, adjust the run configuration to include the following environment variable definitions (replace >>>YOUR API KEY<<< with your own API Key):

    NameValue
    S4_URLhttps://sandbox.api.sap.com/s4hanacloud
    S4_APIKEY>>>YOUR API KEY<<<
    1. Choose RunOpen Configurations. The launch.json file appears.

    2. Modify the Launch Application configuration that was created adding the environment variable definitions. The final configuration will look like the following (replace >>>YOUR API KEY<<< with your own API Key, for example, FDqbnElM7mgmgqbIKBFHRpS1dvpt6sHD. To get your API Key, open https://api.sap.com/api/API_BUSINESS_PARTNER, then log on, and choose Show API Key):

      Code snippet
      {
                  "type": "java",
                  "name": "Launch Application",
                  "request": "launch",
                  "mainClass": "com.example.Application",
                  "projectName": "java-adman-spring-application",
                  "env": {
                      "S4_URL": "https://sandbox.api.sap.com/s4hanacloud",
                      "S4_APIKEY": ">>>YOUR API KEY<<<"
                  }
              }
      Copy code
      Copy the entire content of the java-adman-spring-3-launch-json.txt file [download] to the launch.json file.

    3. Save the launch.json file.

  3. Build, run the application and open the Address Manager page.

    1. Choose TerminalNew Terminal

    2. In the terminal run the following command:

      Code snippet
      mvn clean install -U
      Copy code
      The application project is built including the latest changes.

    3. Go to the Debug tab, select the Launch Application configuration, choose Start Debugging. After a few seconds a pop-up window advises you that A service is listening to port 8080.

    4. Choose Open in New Tab. The application is opened on the welcome page. To access the address manager, in the Web browser, edit the application URL and add at the end the following text:

      Code snippet
      /address-manager/index.html
      Copy code
      The SAP API Business hub sandbox is accessible in read-only mode, so you cannot modify addresses here.

    5. Close the application window, stop the application.

  4. Log on to your SAP S/4HANA Cloud tenant.

    1. In the Web browser (for example, Google Chrome), on your SAP S/4HANA Cloud tenant, access the SAP Fiori Launchpad at [S/4HANA tenant url]/ui, for example (https://my000000.s4hana.ondemand.com/ui). If requested, enter your user and password.

  5. In SAP S/4HANA Cloud, if it is not yet assigned, assign role BR_BUPA_MASTER_SPECIALIST to your user.

    1. In the Home page, choose Search and search for the Maintain Business Users app.

    2. In the app, search for your user and display its details by selecting the line of the list.

    3. In the user detail screen, scroll down and check the Assigned Business Roles section.

    4. If BR_BUPA_MASTER_SPECIALIST is missing from the list, choose Add, search for the BR_BUPA_MASTER_SPECIALIST role, select the box beside it, choose OK, and choose Save.

    5. Select the SAP logo to navigate back to the Home page.

    6. Refresh the Web browser page to see the additional apps provided with the new role.

  6. In SAP S/4HANA Cloud, in the Manage Business Partner Master Data app, create a new business partner based on the following information (replace ### with your user number) if it doesn't already exist:

    FieldValue
    GroupingInternal numbering for standard use
    BP RoleCRM000 Sold-to-party
    First NameJohn
    Last NameDoe ###
    CityNew York
    CountryUS
    LanguageEN
    1. In the home page, search for and open the Manage Business Partner Master Data app.

    2. Choose CreatePerson.

    3. In the Create Person dialog, enter the information provided in the table.

    4. Choose OK

    5. Choose Create.

    6. Select the SAP logo to navigate back to the Home page.

  7. Run the application against your SAP S/4HANA Cloud tenant. Use the following environment variables to configure the connection information (replace ### with your user number):

    NameValue
    S4_URLYour S/4HANA Client tenant URL, for example https://my000000.s4hana.ondemand.com
    S4_USERNAMEADDRESS_MANAGER_###
    S4_PASSWORDWelcomeToTheClouds1!
    Note
    As a prerequisite, for this API to be accessible in the S/4HANA Cloud tenant, you need to execute the previous exercise: Activating the APIs in SAP S/4HANA Cloud.
    1. In your development environment, in the proper run configuration, replace the old environment variables with the new ones provided. The run configuration will display like the following example:

      Code snippet
      {
            "type": "java",
            "name": "Launch Application",
            "request": "launch",
            "mainClass": "com.example.Application",
            "projectName": "java-adman-spring-application",
            "env": {
                  "S4_URL": "https://my000000.s4hana.ondemand.com",
                  "S4_USERNAME": "ADDRESS_MANAGER_###",
                  "S4_PASSWORD": "WelcomeToTheClouds1!"
            }
          }
      Copy code

      Copy the entire content of the java-adman-spring-4-launch-json.txt file [download] to the launch.json file.

    2. Go to the Debug tab, select the Launch Application configuration, choose Start Debugging. After a few seconds a pop-up window displays the following: A service is listening to port 8080.

    3. Choose Open in New Tab. The application is opened on the welcome page. To access the address manager, in the Web browser, edit the application URL and add the following text at the end:

      Code snippet
      /address-manager/index.html
      Copy code
    4. The Address Manager application is opened in read-write mode. Search your John Doe ### business partner and add a new address to it.

      Note
      If the search feature doesn't work, try to access the business partner using the following suffix in the application URL:
      Code snippet
      /address-manager/index.html#/businessPartners/1000000
      Copy code
      Replace 1000000 with your business partner ID.
    5. Stop the application.

  8. Deploy the application to Cloud Foundry.

    1. Choose TerminalNew Terminal. A terminal window appears in the lower part of the screen.

    2. if Cloud Foundry CLI login is required, execute the following commands

      Code snippet
      cf login
      
      Copy code
      Enter your SAP BTP API endpoint, e-mail, and password.

    3. In the Terminal, run the following commands:

      Code snippet
      mvn clean install -U
      cf push
      Copy code
      At the end of the deployment process, you will get a text such as the following:
      Code snippet
           state     since                  cpu     memory         disk           details
      #0   running   2020-04-24T17:25:03Z   66.4%   167.5M of 1G   152.4M of 1G
      Copy code

  9. In the SAP BTP Cockpit, in the application, configure the environment variables to run against the SAP API Business Hub Sandbox, then open the application.

    1. In Google Chrome, open the URL https://account.hanatrial.ondemand.com. If required, enter your e-mail and password.

    2. In the SAP BTP Cockpit, choose Enter Your Trial account. Navigate to your trial Subaccount. Navigate to the dev space.

    3. Choose the java-adman-spring application name.

    4. In the Application: java-adman-spring - Overview page, go to the User-Provided Variables tab. Add the following variables (replace >>>YOUR API KEY<<< with your own API Key, for example FDqbnElM7mgmgqbIKBFHRpS1dvpt6sHD.

    5. To get your API Key, open https://api.sap.com/api/API_BUSINESS_PARTNER, then log on, and choose Show API Key):

      KeyValue
      S4_URLhttps://sandbox.api.sap.com/s4hanacloud/
      S4_APIKEY>>>YOUR API KEY<<<
    6. Go to the Overview tab.

    7. Restart the application.

    8. Choose the Application Route. The application opens in the Welcome page.

    9. Add /address-manager/index.html at the end of the browser URL. The Address Manager application is opened, reading the data from the SAP API Business Hub Sandbox system.

  10. In Cloud Foundry, create an instance of the Destination service named my-destinations if it doesn't exist already.

    1. In the SAP BTP Cockpit, navigate to the trial subaccount, then to the dev space.

    2. In the dev space, navigate to ServicesInstances tab.

    3. In the Space:dev - Service Instances screen, Choose Create. Create a new instance based on the following information:

      FieldValue
      ServiceDestination Service
      Service Planlite
      Instance Namemy-destinations
  11. Bind the my-destinations service to the java-adman-spring application.

    1. In the SAP BTP Cockpit, navigate to the dev space, then to the java-adman-spring application.

    2. In the Application: java-adman-spring - Overview page, go to the Service Bindings page.

    3. Choose Bind Service.

    4. Select Service from the catalog. Choose Next.

    5. Choose the Destination service. Choose Next.

    6. Choose the Re-use existing instance. Select the my-destinations Instance. Choose Next.

    7. Choose Finish.

  12. In the my-destinations service, in case it doesn't already exist, create a destination named sandbox, referring to the SAP API Business Hub Sandbox.

    1. Return to the main page of the dev space, navigate to ServicesInstances page. Choose the my-destinations instance. Click on Manage Instance

    2. Choose the Destinations page.

    3. Chose New Destination create a destination based on the following information:

      FieldValue
      Namesandbox
      TypeHTTP
      DescriptionSAP API Business Hub sandbox system
      URLhttps://sandbox.api.sap.com/s4hanacloud
      Proxy TypeInternet
      AuthenticationNoAuthentication
  13. Adapt the environment variables of your application so that it reads the system information from the Destination Service. Restart and open the application again.

    1. Navigate to the dev space, then to your application, then to the User-Provided Variables tab.

    2. Delete the S4_URL variable.

    3. Enter a new variable with the S4_DESTINATION name and sandbox value .

    4. Go to the Overview page.

    5. Restart the application.

    6. Choose the Application Route. The application opens in the Welcome page.

    7. Add /address-manager/index.html at the end of the browser URL. The Address Manager application is opened, reading the data from the SAP API Business Hub Sandbox system, configured via the sandbox destination in the my-destinations service.

  14. In the my-destinations service, create a destination named s4cloud, referring to your SAP S/4HANA Cloud tenant if it doesn't already exist.

    1. Return to the main page of the dev space, navigate to ServicesInstances page. Choose the my-destinations instance. Click on Manage Instance

    2. Choose the Destinations view.

    3. Chose New Destination create a destination based on the following information (replace ### with your user number, replace the URL value with your own SAP S/4HANA Cloud tenant URL):

      FieldValue
      Names4cloud
      TypeHTTP
      DescriptionSAP S/4HANA Cloud tenant
      URLYour S/4HANA Client tenant URL, for example https://my000000.s4hana.ondemand.com
      Proxy TypeInternet
      AuthenticationBasicAuthentication
      UserADDRESS_MANAGER_###
      PasswordWelcomeToTheClouds1!
  15. Adapt the environment variables of your application so that it reads the s4cloud system information from the Destination service. Restart and open the application again.

    1. Navigate to the dev space, then to your application, then to the User-Provided Variables tab.

    2. Change the value of the S4_DESTINATION variable to s4cloud.

      Optionally, delete the S4_APIKEY variable.

    3. Go to the Overview tab.

    4. Restart the application.

    5. Choose Application Route. The application opens on the Welcome page.

    6. Add /address-manager/index.html at the end of the browser URL.

    7. The Address Manager application is opened, reading the data from your SAP S/4HANA Cloud tenant, configured via the s4cloud destination in the my-destinations service. Search your John Doe ### business partner and add a new address to it.

Save progress to your learning plan by logging in or creating an account