Skip to Content
Technical Articles
Author's profile photo Gunter Albrecht

RFC meets the Web: Part II – Building the proxy

RFC meets Web – Part II: How to build the proxy

Welcome back to the second blog post where we look into building the REST2RFC proxy! It’s a SAP Cloud SDK Java application running on SAP BTP Cloud Foundry runtime.

Introduction and BTP services used

When I started with the project (which was inspired by customers telling me “we don’t have APIs, we are still on S/4HANA 1909”) I explored the options to build a proxy to translate between the RFC and the REST world. A few things became clear:

  • That proxy must be agnostic – no function module specific logic should be in it, so it can be universal.
  • REST is channeled through SAP Cloud Connector and with that we have a granular way to white-list what should be exposed from the on-premise system.
  • SAP BTP offers the RFC-flavor for defining a destination. Great!
  • Using BTP RFC destinations only works through Java and the API For SAP BTP (Java Web Tomcat 9) which is not in the SAP Cloud SDK for Java (not to be confused with the JCo you can download as a separate package) and likely coming from Neo but working perfectly fine with CF and latest Cloud SDK, too.
  • All existing tutorials were outdated that explained the RFC integration so I hope this blog helps you.

As for the BTP project building the application needs these services:

  1. Authorization and Trust Management Service (xsuaa): Securing the application from the web entry point with OAuth2 and roles to be assigned to a user which define the scope during authentication as part of the JWT.
  2. Connectivity Service: To connect between cloud and on-premise through the Cloud Connector (CC).
  3. Destination Service: To retrieve the destinations in the Java app for RFC and offer the REST service to the caller.
  4. Application Logging Service: To allow for a really nice monitoring of the proxy. Not mandatory but I highly recommend it for debugging and day-to-day monitoring.

Proxy project details

Development IDE

I used Eclipse in connection with the SAP Cloud SDK for Java. You want to install Maven with

$ choco install maven

on a Windows device. To create a fresh project I ran

mvn archetype:generate "" "-DarchetypeArtifactId=scp-cf-tomee" "-DarchetypeVersion=RELEASE"

since I built on TomcatEE and not Springboot. This create the framework you should open in Eclipse once done.

I deleted those elements which I didn’t need (like junit and integration tests 😂) so the build process just considered my code. You also need to define a manifest file and the obligatory xs-security.json.


- name: jco-rfc-rest-server
  memory: 1500M
  timeout: 300
  random-route: true
  path: application/target/jco-rfc-rest-server-application.war
    - sap_java_buildpack
    USE_JCO: "true"
    TARGET_RUNTIME: tomee7
    JBP_CONFIG_SAPJVM_MEMORY_SIZES: 'metaspace:128m..'
    xsuaa_connectivity_instance_name: "jco-rfc-rest-server-xsuaa"
    connectivity_instance_name: "jco_connectivity"
    destination_instance_name: "jco_destination"
    - jco-rfc-rest-server-xsuaa
    - jco_connectivity
    - jco_destination
    - jco-app-logging

above is my manifest.yml.

  "xsappname": "jco-rfc-rest-server",
  "tenant-mode": "dedicated",
  "scopes": [
      "name": "$XSAPPNAME.Display",
      "description": "GET requests on BAPI"
      "name": "$XSAPPNAME.Modify",
      "description": "POST requests on BAPI"
  "role-templates": [
      "name": "JCo-REST-RFC-Server-Viewer",
      "description": "Required to run GET requests for RFC BAPI calls.",
      "scope-references"     : [
      "name": "JCo-REST-RFC-Server-Administrator",
      "description": "Required to run POST requests for RFC BAPI calls.",
      "scope-references"     : [

Above is my xs-security.json. Based on that you can create 2 role collections in BTP later to allow for a display and and admin role for the proxy calls.

Java specifics: Authority checks

The Java class for the proxy is based on the HttpServlet class. Below I’d like to share the pattern for authority checks.

@ServletSecurity(@HttpConstraint(rolesAllowed = { "Display", "Modify" }))
public class Rest2RfcProxy extends HttpServlet {

        // .... some code

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {	
               // ...

	@RolesAllowed({"Display", "Modify"})
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
               // ...

        // .... some more code


So that’s how the security scopes defined in xs-security.json are checked in the Java code. You must enable that in the web.xml file of the webapp like so:


            <web-resource-name>Baseline Security</web-resource-name>


Only then it will work with the data injected by the JWT.

Info: Per default BTP destination service will work with X-CSRF token. I turned it off for testing – this is also defined in web.xml!

Java specifics: JCo REST/RFC

The communication through JCo via RFC follows this sequence:

  1. Get the RFC destination with details that we specified in the SAP BTP (see the first blog).
  2. Define the function to be called in Java.
  3. Define the import/ export and table parameter list from the function module. These variables hold the according structures.
  4. Load the metadata of the 3 objects from the SAP ECC or S/4HANA data dictionary.
  5. Set the import or tables parameters as needed.
  6. Execute the function module call.
  7. If it’s a POST, also execute a call to BAPI BAPI_TRANSACTION_COMMIT. If you call a Z-function module it depends how your organized your LUW whether this has any impact at all. Certainly it won’t hurt but the commit might have been done before that in your ABAP code.
  8. Feed back the data to the caller

Example for the IMPORTS:

if (jImports != null) {"Filling BAPI import: " + jImports.toString());

This uses the .fromJSON method to fill the structure. On the way back to the caller you can then use the .toJSON method to obtain the JSON data for REST.

Application logging

I recommend to consider using the application logging service on BTP, particularly for this middleware application to facilitate error analysis. It builds on the common org.slf4j framework. You activate it with

private static final Logger logger = LoggerFactory.getLogger(<your class name>.class);

declared on class level to have it available in every method and exception. In the manifest.yml you can then set the logging level:


here it means everything is logged. You can reduce it to WARN or ERROR.


Image 1: Application Logging service on BTP

The dashboard offers detailed filtering and statistics which are very handy.


Image 2: Application logging dashboard overview


I faced a few issues when developing and building it because the tutorials were outdated or didn’t support the use case. Maybe this can help you.


“java.lang.UnsupportedClassVersionError: com/sap/demo/jco/ConnectivityRFCExample has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0 (unable to load class [])

This means the bytecode of the WAR file isn’t matching the BTP Java Buildpack. First you want to check the buildpack on BTP:

$ cf buildpacks

E.g. 52.0 = Java 8, 61.0 = Java 17. I had to set my Eclipse JDK to create code for 52.0 by setting it to Java 8 from Java 17. Also this help is useful (standard is Java 8, if using SAP Machine it’s Java 11).

POST, PUT, PATCH. DELETE will require X-CSRF-Token

If you don’t want that, turn it off, out-comment the section for the filter RestCsrfPreventionFilter in web.xml. This can help during testing. For production, better put it back in.

After setting up a fresh project with Maven Eclipse looks “funny”

You got to switch the facet in the project properties to Java.

Maven repository not found

Add it to the Java Build Path in the project’s properties.


Image 3: Project properties, Java build path

“Where is the source code?”

Please check my LinkedIn post in that matter.


Building a proxy to translate between the RFC and REST world requires an agnostic proxy. It is a universal solution without function module specific logic, and the REST service is channeled through the SAP Cloud Connector. Using the RFC-flavor for defining a destination on the SAP BTP platform with Java Web Tomcat 9 API allowed for easy integration. By following this blog, building an efficient proxy is now possible, and it will be useful for businesses using older SAP S/4HANA or ECC systems.

Let me know your feedback – I’m eager to learn how you are using the approach for your web use cases!


Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Ulrich Schmidt
      Ulrich Schmidt

      I would like to add a few thoughts by comparing your "modern" approach with a very old solution that has been developed 24 years ago for pretty much the same purpose: making RFC-enabled function modules accessible from web applications.

      Here, we basically have 4 components:

      REST client  ---> REST-to-RFC Converter (running on BTP) ----> Cloud Connector  --->  ABAP backend

      In the older approach (first shipped to customer in April 1999) we combined the two middle components (the "REST Proxy", which converts from the web standard protocols (REST/HTTP) to RFC, and the Cloud Connector, which exposes the on-premise system to the web in a secure way) into one single component called "SAP Business Connector".

      SAP BC then provided the following functionality:

      • a generic XML-to-RFC converter for any function module (as well as for all IDoc types)
      • a layer for RFC access to SAP systems (this is what later was named "JCo" and distributed separately from SAP BC...)
      • a kind of "reverse proxy" functionality allowing secure incoming connections from the internet
      • an XML template generator -- This made it very easy for web clients to consume the RFC-enabled function modules. With one button-click, you could generate an XML template for the FM/BAPI you wanted to call, and the web client then only needed to fill the imports.

      The architecture could therefore be simplified by one hop:

      XML client ---> Business Connector ---> ABAP backend

      Author's profile photo Gunter Albrecht
      Gunter Albrecht
      Blog Post Author

      Absolutely - many roads lead to Rome. 👍

      With this approach comes role-based authorization and xsuaa-authentication with a HTTP destination that can be consumed by other BTP applications.

      Author's profile photo Saurabh Tiwari
      Saurabh Tiwari

      Impressive ! Good enough detail !

      Author's profile photo Junjie Tang
      Junjie Tang

      Thanks for the great blog post.

      Unfortunately, the RFC maven modules of the SAP Cloud SDK have been deprecated (reference).

      The SDK offered some wrapper functions to consume JCo, which is not a required dependency.

      Here is the link to the JCo documentation, so the users can consume JCo APIs directly.