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: 
remi_astier
Advisor
Advisor

The recommendation from SAP for extension development is to use cloud application programming (CAP). In addition to data definition, it makes it queryable and writable over odata or rest protocol without coding. This is useful because the service can serve web applications, be exposed to internal applications, or even be associated with SAP API management to interface with customers and partners systems.


However great is CAP, geospatial data is often consumed differently. Visualization tools like qgis or dbeaver establish a direct connection to SAP HANA. GIS platforms like geoserver or Esri ArcGIS can publish data as layers over various web service protocols.


We came across a customer in the forest industry that needed to develop mutliple S/4 extensions  and therefore would use CAP. They also needed to query, process and expose geospatial data. There requirements were:




  • Data is stored only once, no copy in a different GIS system.

  • A single API to expose the data to a web interface as well as other applications

  • Data exposed in read and write

  • Data modificiations must go through multiple checks and retain transactional consistancy


Those requirements made it difficult to use a traditional GIS middleware so we proved this could be done with CAP and following architecture:

CAP architecture

Architecture with CAP


The geospatial data resides in HANA tables which can be local, a cached replica or remote, depending on the business needs. Stored Procedures and views are useful artifacts that are typically used in conjunction with spatial data types.

Functions/API represented on the right orange box perform various business logic:

  • records containing any form of address field will benefit from geocoding to add coordinates and normalized fields such as country, state, county, city...

  • A polygon representing a harvesting block is checked for an intersection with a powerlines.

  • A polygon representing a harvesting block along with a harvest date range is checked for overlapping with wildlife sanctuary zones and seasons.


The purpose of using functions outside the CAP main module is to simplify developments, releases, even improve scalability if using serverless functions and micro services APIs.

Lastly, the CAP service layer is the main component. It holds 3 important artifacts:

In the service extension file, we handle the geospatial format conversions: the value in and out of the HANA table is in binary format and we prefer the service layer to use a human readable format such as geojson or Well Known Text (WKT).

Example of web service requests are in the samples folder. For instance, adding a warehouse is done by posting to <host>/forest/WareHouse this body:
{"ID": 1, "label": "Warehouse 1", "address": "okipii, Finland" }

Geocoding is performed before the record is inserted, to check the result, you can simply fetch the record with a get request to <host>/forest/Warehouse?$filter=label%20eq%20'Warehouse 1'

The column geo_score with a value of 0.99 indicates that the geocoding is accurate.
HTTP/1.1 200 OK
OData-Version: 4.0
content-type: application/json;odata.metadata=minimal
Date: Tue, 07 Sep 2021 13:41:27 GMT
Connection: close
Content-Length: 297

{
"@odata.context": "$metadata#Warehouse/$entity",
"ID": 1,
"label": "Warehouse 1",
"surface": null,
"address": "okipii, Finland",
"geo_score": 0.99,
"geo_point": {
"type": "Point",
"coordinates": [
22.59858989715576,
62.495699882507324
]
},
"geo_city": "Kurikka",
"geo_county": "Etelä-Pohjanmaa",
"geo_country_iso3": "FIN"
}

A more fun example is to have a look at the wild life sanctuaries defined and post a harvesting block inside a sanctuary during the protected season:
### Harvesting block in a protected area during a specific season.
POST http://localhost:4004/forest/HarvestingBlock
Content-Type: application/json


{"ID":2,"dt":"2022-10-10","geom_as_wkt":"POLYGON ((23.77344846725464 61.42467889322534, 23.77394199371338 61.425407593025284, 23.77162456512451 61.426126012789695, 23.77134561538696 61.42581812063022, 23.771259784698486 61.425161273869925, 23.77145290374756 61.42508943041672, 23.77344846725464 61.42467889322534))"}


The response returns the id of the first rule that was infringed:
HTTP/1.1 500 Internal Server Error
OData-Version: 4.0
content-type: application/json;odata.metadata=minimal
Date: Tue, 07 Sep 2021 14:11:37 GMT
Connection: close
Content-Length: 138

{
"error": {
"code": "500",
"message": "Harvesting in this location and date infringes the sanctuary \"Little Trolls of the woods in Autumn\""
}
}

 

The sample project with full code and example data is available on github. I'd be happy to take this further and build a UI on top unfortunately I have zero UI5 skills so I'd be happy to get some help!

 
1 Comment