How to implement
Deep Insert
in
SAP Cloud Application Programming Model
with deep insert on remote service
using SAP Cloud SDK
Quicklinks:
Project Files
Part 1: Intro
Part 2: UUID
Part 3: Multi-Level
Part 4: Previous Tutorial
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>sdk-bom</artifactId>
<version>2.19.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>s4hana-all</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
</dependencies>
java
-jar odata-generator-cli-2.19.1.jar
-- input-dir
-- output-dir
-- package-name-prefix
--use-odata-names
DefaultGwsampleService service = new DefaultGwsampleService();
ErpConfigContext config = new ErpConfigContext("ES5Destination");
SalesOrder createdV2SalesOrder = service.createSalesOrder(salesOrderToCreate).execute(config);
v4ResponseMap.put("orderId", v2ResponseSalesOrder.getSalesOrderID());
List<SalesOrderLineItem> itemList = v2ResponseSalesOrder
.getLineItemsIfPresent()
.get();
package com.example;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.example.proxies.namespaces.gwsample.SalesOrder;
import com.example.proxies.namespaces.gwsample.SalesOrderLineItem;
import com.example.proxies.services.DefaultGwsampleService;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.s4hana.connectivity.ErpConfigContext;
import com.sap.cloud.sdk.service.prov.api.exception.DatasourceException;
import com.sap.cloud.sdk.service.prov.api.operations.Create;
import com.sap.cloud.sdk.service.prov.api.request.CreateRequest;
import com.sap.cloud.sdk.service.prov.api.response.CreateResponse;
import com.sap.cloud.sdk.service.prov.api.response.ErrorResponse;
public class ServiceImplementation {
private static Logger logger = LoggerFactory.getLogger(ServiceImplementation.class);
@Create(entity = "OrderEntity", serviceName = "RelationService")
public CreateResponse createSalesOrder(CreateRequest createRequest) throws DatasourceException{
// 1) access the payload from request body, which is OData V4
Map<String, Object> v4RequestMap = createRequest.getData().asMap();
// 2) compose the payload to be sent to remote OData V2 service
SalesOrder salesOrder = convertV4RequestPayloadToV2(v4RequestMap);
try {
// 3) send request to v2 service
DefaultGwsampleService service = new DefaultGwsampleService();
ErpConfigContext config = new ErpConfigContext("ES5Destination");
SalesOrder createdV2SalesOrder = service.createSalesOrder(salesOrder).execute(config);
// 4) convert v2 response back to v4
Map<String, Object> v4ResponseMap = convertV2ResponsePayloadToV4(createdV2SalesOrder);
// 5) compose the V4 response of our service
return CreateResponse.setSuccess().setData(v4ResponseMap).response();
} catch (ODataException e) {
return CreateResponse.setError(ErrorResponse.getBuilder()
.setMessage(e.getMessage())
.setStatusCode(501)
.setCause(e)
.response());
}
}
/* HELPERS */
// handle the full payload, the parent entity (SalesOrder) including nested inline list of children (LineItems)
private SalesOrder convertV4RequestPayloadToV2(Map<String, Object> v4RequestMap){
// map the v4 property names to v2 and, in addition, fill some non-nullable fields
SalesOrder salesOrder = new SalesOrder();
salesOrder.setNote((String)v4RequestMap.get("commentOnOrder"));
salesOrder.setCustomerID("0100000000");
salesOrder.setCurrencyCode("USD");
// now handle the deep insert, the nested inline list of maps
List<Map<String, Object>> v4InlineItemsList = (List<Map<String, Object>>)v4RequestMap.get("linkToItems");
List<SalesOrderLineItem> salesOrderLineItemList = convertV4InlineListToV2(v4InlineItemsList);
salesOrder.setLineItems(salesOrderLineItemList);
return salesOrder;
}
// inline list: SalesOrderLineItem collection
private List<SalesOrderLineItem> convertV4InlineListToV2(List<Map<String, Object>> v4InlineItemsList){
// the nested inline data is a list, because of to-many association
List<SalesOrderLineItem> v2InlineItemsList = new ArrayList<SalesOrderLineItem>();
// loop through all v4 line items in order to map them to v2
for (Map<String, Object> v4InlineMap : v4InlineItemsList) {
SalesOrderLineItem v2InlineMap = convertV4InlineMapToV2(v4InlineMap);
v2InlineItemsList.add(v2InlineMap);
}
return v2InlineItemsList;
}
// inline Map: single SalesOrderLineItem entry
private SalesOrderLineItem convertV4InlineMapToV2(Map<String, Object> v4InlineMap){
SalesOrderLineItem item = new SalesOrderLineItem();
item.setQuantity((BigDecimal)v4InlineMap.get("numberOfProductsInOrder"));
item.setProductID((String)v4InlineMap.get("productForOrder"));
item.setDeliveryDate(LocalDateTime.now());
item.setCurrencyCode("USD");
item.setItemPosition("0000000010");
return item;
}
// response of V2 deep insert contains a SalesOrder with expanded list of LineItems
private Map<String, Object> convertV2ResponsePayloadToV4(SalesOrder v2ResponseSalesOrder) throws ODataException{
Map<String, Object> v4ResponseMap = new HashMap<String, Object>();
v4ResponseMap.put("orderId", v2ResponseSalesOrder.getSalesOrderID());
v4ResponseMap.put("commentOnOrder", v2ResponseSalesOrder.getNote());
// the response of deep insert is a $expand
List<SalesOrderLineItem> v2ResponseInlineItemList = v2ResponseSalesOrder.getLineItemsIfPresent().get();
// convert it to v4
List<Map<String, Object>> v4ResponseInlineList = convertV2InlineListToV4(v2ResponseInlineItemList);
// add the associated entities to our parent map
v4ResponseMap.put("linkToItems", v4ResponseInlineList);
return v4ResponseMap;
}
private List<Map<String, Object>> convertV2InlineListToV4(List<SalesOrderLineItem> v2ResponseInlineList){
List<Map<String, Object>> v4ResponseInlineList = new ArrayList<Map<String, Object>>();
for(SalesOrderLineItem salesOrderLineItem : v2ResponseInlineList){
Map<String, Object> v4ResponseInlineMap = convertV2InlineMapToV4(salesOrderLineItem);
v4ResponseInlineList.add(v4ResponseInlineMap);
}
return v4ResponseInlineList;
}
// convert inline entry of V2 SalesOrderLineItem to V4 Map
private Map<String, Object> convertV2InlineMapToV4 (SalesOrderLineItem v2LineItem){
Map<String, Object> v4ResponseInlineMap = new HashMap<String, Object>();
v4ResponseInlineMap.put("linkToOrder_orderId", v2LineItem.getSalesOrderID());
v4ResponseInlineMap.put("itemId", UUID.randomUUID() );
v4ResponseInlineMap.put("productForOrder", v2LineItem.getProductID());
v4ResponseInlineMap.put("numberOfProductsInOrder", v2LineItem.getQuantity());
return v4ResponseInlineMap;
}
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sap.cloud.servicesdk.prov</groupId>
<artifactId>projects-parent</artifactId>
<version>1.30.1</version>
</parent>
<artifactId>DeepInsertRemote-srv</artifactId>
<groupId>customer</groupId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>DeepInsertRemote-srv</name>
<properties>
<packageName>com.example</packageName>
</properties>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<executable>npm</executable>
<workingDirectory>${project.basedir}/../</workingDirectory>
</configuration>
<executions>
<execution>
<id>npm install</id>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>npm run build</id>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>connection.properties</exclude>
</excludes>
</resource>
</resources>
</build>
<profiles>
<profile>
<activation>
<property>
<name>devmode</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<webResources combine.children="append">
<resource>
<directory>${project.build.sourceDirectory}</directory>
<targetPath>sources</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>only-eclipse</id>
<activation>
<property>
<name>m2e.version</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sap.db.jdbc</groupId>
<artifactId>ngdbc</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<versionRange>[1.6.0,)</versionRange>
<goals>
<goal>exec</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
<!-- Required when using SAP Cloud SDK -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>sdk-bom</artifactId>
<version>2.19.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>s4hana-all</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
</dependencies>
</project>
namespace com.relation;
entity OrderEntity {
key orderId: String;
commentOnOrder: String;
linkToItems : Composition of many ItemEntity on linkToItems.linkToOrder = $self;
}
entity ItemEntity {
key itemId: UUID;
productForOrder: String;
numberOfProductsInOrder: Decimal(5, 2);
linkToOrder : Association to OrderEntity;
}
using com.relation from '../db/data-model';
service RelationService {
@cds.persistence.skip
entity OrderEntity as projection on relation.OrderEntity;
@cds.persistence.skip
entity ItemEntity as projection on relation.ItemEntity;
}
_schema-version: 2.0.0
ID: DeepInsertRemote
version: 1.0.0
modules:
- name: DeepInsertRemote-db
type: hdb
path: db
parameters:
memory: 256M
disk-quota: 256M
requires:
- name: DeepInsertRemote-db-hdi-container
- name: DeepInsertRemote-srv
type: java
path: srv
parameters:
memory: 990M
provides:
- name: srv_api
properties:
url: ${default-url}
requires:
- name: DeepInsertRemote-db-hdi-container
properties:
JBP_CONFIG_RESOURCE_CONFIGURATION: '[tomcat/webapps/ROOT/META-INF/context.xml:
{"service_name_for_DefaultDB" : "~{hdi-container-name}"}]'
- name: DeepInsertRemote-uaa
- name: ES5Destination
group: destinations
properties:
name: ES5Destination
url: '~{url}'
username: '~{username}'
password: '~{password}'
resources:
- name: DeepInsertRemote-db-hdi-container
type: com.sap.xs.hdi-container
properties:
hdi-container-name: ${service-name}
- name: DeepInsertRemote-uaa
type: org.cloudfoundry.managed-service
parameters:
service-plan: application
service: xsuaa
config:
xsappname: DeepInsertRemote-${space}
tenant-mode: dedicated
- name: ES5Destination
properties:
url: https://sapes5.sapdevcenter.com
username: your_ES5_username
password: your_ES5_password
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
31 | |
24 | |
8 | |
7 | |
7 | |
6 | |
6 | |
5 | |
5 | |
4 |