Skip to Content

Part of the beauty of creating Cloud-based SAPUI5 apps is the abstraction of URLs away from the application. It is possible, using destinations in SAP Cloud, to connect through to multiple destinations including different S/4HANA and / or SAP ECC instances (when using Cloud Connector).

In SAP Cloud you can create Destinations – these can leverage your Cloud Connector or can point to other destinations on the internet.

I set up 2 Cloud to On-Premise mappings on my Cloud Connector subaccount. These point to my 2 Frontend Servers that reach into my other on-premise systems. (The installation of Cloud Connector is simple – it can be setup on your laptop even! – refer here for more detail).

These now appear in my SAP Cloud account as shown below:

TIP Right-click any image and Select “Open Image in New Tab” to see a clearer view of the image.

I was interested in connecting to both my QA Server as well as my DEV server in the same SAPUI5 app.

Because I wish to consume these “Back-End Systems” (as described above by SAP Cloud Platform  – they are best described (from my perspective) as on-premise Front-End Systems that expose my SAP Back-End Systems – because of the Hub Deployment pattern for SAP Gateway implemented in our landscape) with my SAPUI5 app I need to create destinations to the Cloud connector. As a reminder, Connectivity Destinations abstract connectivity away from all of your applications so that there is no URL wiring required in your apps.

After configuring destinations I now have the following destinations that have been tested for connectivity:

Above is the Destination to the on-Prem DEV Front-End Server with the properties for use within SAPWebIDE configured. The QA box is as shown below (without the detail). NB! Remember to match your LocationID to the on configured on your on-Prem Cloud Connector Administration Console. While it is not shown in the earlier screenshot of the Cloud Connector console it is an optional field.

We are now ready to use services from all SAP Servers that we have on prem. Wiring up the services in Gateway has been done. I can cover this in a follow-up post if required. I am employing out of the box S4HANA 1709 odata APIs for the purposes of this excercise. e.g. the Business Partner oData API  You could expose your own services including services created on an ECC box.

Fire up SAPWebIDE and Create a new SAPUI5 Application as below (using a template and selecting the option as highlighted below).

 

Now we simply add 2 models to our solution – one that consumes the Business Partner API on the Dev Server and one that consumes the Business Partner API on the QA Server. Follow the arrow sequence starting with selecting the application you just created.

Screenshot: SAPWebIDE – Adding Data Sources to the SAPUI5 Application

ReminderRight-click any image and Select “Open Image in New Tab” to see a clearer view of the image.

When selecting one of the servers you may be required to authenticate as I (and therefore maybe you) didn’t key in credentials when we set up the destination.

 

Once authenticated you will have access to the services – narrow the search by filtering (below I filtered with “BUS”). Below I am wiring up the Business Partner service exposed on the QA Front-End Server – this service call points to our remote s4hana 1709 Back-end Server but is exposed and mapped to the “remote server” on SAP Gateway.

This is where SAPWebIDE “drops the ball”. It incorrectly reports that this service already exists – it has failed to recognise that these services represent two different destinations (making them therefore quite distinct.

SAPWebIDE makes entries in 2 files when adding a datasource and then an associated model. The manifest.json and the neo-app.json file.

The neo-app.json file records the destination records that will be used in the app. These destinations appear to be keyed on the path and on this basis SAPWebIDE decides that it wants to overwrite my existing destination. More on resolving this later.

In the manifest.json my previous datasource was overwritten (as I had to chose this option) – the above dialog refers.

"dataSources": {
	"API_BUSINESS_PARTNER": {
		"uri": "/sap/opu/odata/sap/API_BUSINESS_PARTNER/",
		"type": "OData",
		"settings": {
			"odataVersion": "2.0",
			"localUri": "localService/API_BUSINESS_PARTNER/metadata.xml"
		}
	}
}

I added my other datasource back and appended a single letter (Q for QA and D for DEV) to distinguish between the two datasources. (Of interest was that the metadata.xml folder had a sub-folder created and the ‘other’ API_BUSINESS_PARTNER metadatafile was created there – so at least this was not overwritten / deleted – you can see the 2 distinct files in the entries for localUri below. The are likely identical but I dare not risk using just one at this point.

"dataSources": {
    "API_BUSINESS_PARTNERQ": {         // added a "Q" at end 
        "uri": "/sap/opu/odata/sap/API_BUSINESS_PARTNER/",
        "type": "OData",
        "settings": {
            "odataVersion": "2.0",
            "localUri": "localService/metadata.xml"
        }
    },
    "API_BUSINESS_PARTNERD": {                                  // added a "D" at end
        "uri": "/sap/opu/odata/sap/API_BUSINESS_PARTNER/",      // same as above (for now)
        "type": "OData",
        "settings": {
            "odataVersion": "2.0",
            "localUri": "localService/API_BUSINESS_PARTNER/metadata.xml"    // distinct metadata.xml
        }
    }
}

The two distinct datasources now appear nicely one below the other as depicted below.

I can now create distinct models off the separate datasources.

While I still need to resolve the destination question, which I will get to shortly, below is a concise view of my model creation process.  For a more detailed blog on model creation please refer here.

The 2 models are created as depicted below – (2) refers

The manifest.json is all good with this as this point – my two named data models are depicted below.

"models": {
    "i18n": {
        "type": "sap.ui.model.resource.ResourceModel",
        "settings": {
            "bundleName": "blt.ui5MultiInstanceConsumer.i18n.i18n"
        }
    },
    "dev_bp": {                                         // named model 1
        "type": "sap.ui.model.odata.v2.ODataModel",
        "settings": {
            "defaultOperationMode": "Server",
            "defaultBindingMode": "OneTime",
            "defaultCountMode": "Request"
        },
        "dataSource": "API_BUSINESS_PARTNERD",         // pointer to datasource
        "preload": true
    },
    "qa_bp": {                                        // named model 2
        "type": "sap.ui.model.odata.v2.ODataModel",
        "settings": {
            "defaultOperationMode": "Server",
            "defaultBindingMode": "OneTime",
            "defaultCountMode": "Request"
        },
        "dataSource": "API_BUSINESS_PARTNERQ",
        "preload": true
    }

I created a very simple UI to expose data from the respective models – simply add this to the only page in your solution (the Main.view.xml). (the only “code” we do!)

<content>
   <l:HorizontalLayout>
    <Label class="sapUiSmallMargin" text="DEV"/>
	<Select class="sapUiSmallMarginEnd" id="selectDevPartner" enabled="true" 
		items="{ path: 'dev_bp>/A_BusinessPartner' }" 
		change="handlePartnerSelectionChange">
	   <core:Item key="{dev_bp>BusinessPartner}" text="{dev_bp>BusinessPartnerName}"/>
	</Select>
    <Label class="sapUiSmallMargin" text="QA"/>
	<Select class="sapUiSmallMarginEnd" id="selectQaPartner" enabled="true" 
		items="{ path: 'qa_bp>/A_BusinessPartner' }">
	   <core:Item key="{qa_bp>BusinessPartner}" text="{qa_bp>BusinessPartnerName}"/>
	</Select>
   </l:HorizontalLayout>
</content>

I feel like I am almost ready to trigger a service call from the cloud through to the two distinct servers.

Firstly I want to prevent batching so that I can see the individual calls easily.

// under models section in manifest.json
"dev_bp": {
    "type": "sap.ui.model.odata.v2.ODataModel",
    "settings": {
        "useBatch" : false,                   // added this line
        "defaultOperationMode": "Server",
        "defaultBindingMode": "OneTime",
        "defaultCountMode": "Request"
    },
    "dataSource": "API_BUSINESS_PARTNERD",   // data source for model
    "preload": true
}

Before I pull the trigger I want to resolve the destination issue. I need to ‘point’ the two models at distinct destinations. The models provide a pointer to the datasource. (above).

It seems that the models do pattern matching on the early part of the datasource URI (refer the datasource entries in the manifest.json earlier and then further below for the amended ones) to locate the destination entry in the neo-app.json.

On this basis I will change the “path” attribute of the destination in the neo-app.json file.

I will first create two entries in the “neo-app.json”  from the one.

(Neo-app.json is the configuration file managing our destinations as they exist in SAP Cloud Platform.)

These should match the destinations created earlier in SAP Cloud Platform

{
  "path": "/sap/opu/odatad",          // was -> "/sap/opu/odata" - should not but is the key 
  "target": {
    "type": "destination",
    "name": "DEVFES",                 // my DEV Frontend server (Destination in SAP Cloud)
    "entryPath": "/sap/opu/odata"     // this must stay as this is the real path
  },
  "description": "OnPrem DEV FES"
},
{
  "path": "/sap/opu/odataq",          // was -> "/sap/opu/odata" not the q suffix
  "target": {
    "type": "destination",
    "name": "QAFES",                  // my QA Frontend server 
    "entryPath": "/sap/opu/odata" 
  },
  "description": "OnPrem QA FES"
}

Now I just need to edit the datasources in my manifest.json that my models are pointing to. The models need to point to the distinct destinations. Below are the edits required.

"dataSources": {
   "API_BUSINESS_PARTNERQ": {
       "uri": "/sap/opu/odataq/sap/API_BUSINESS_PARTNER/",  //change here odata -> odataq
	"type": "OData",
	"settings": {
	   "odataVersion": "2.0",
	   "localUri": "localService/metadata.xml"
	}
   },
   "API_BUSINESS_PARTNERD": {
 	"uri": "/sap/opu/odatad/sap/API_BUSINESS_PARTNER/",  //change here odata -> odatad
	"type": "OData",
	"settings": {
	   "odataVersion": "2.0",
	   "localUri": "localService/API_BUSINESS_PARTNER/metadata.xml"
	}
   }
}

Running the app I should now I have two dropdowns with data from the two distinct backend servers (in my case they are QA and DEV but they could be 2 production servers and they need not be s4hana 1709 servers).

It works! The data looks identical:

Let’s check out the calls from the browser (as viewed with Chrome running the dev tools.

So if I go in and edit the ALPHA SUPERSPAR Business Partner record on the DEV Backend (s4hana) server I should have a difference showing on a browser reload. Again, for clarity, as much as I am connecting via cloud connector to the Frontend server that is hosting Gateway, Gateway simply maps the call to my backend server.

Edit the business partner below:

And now refresh the UI5 App:

And all is now done.

In conclusion:

The point of this exercise was not to offer up a great functional app but just to understand and resolve the issue I had with SAPWebIDE refusing to allow me to consume the same oData endpoint on 2 distinct servers.

This article provides a workaround for the current restriction.

It does however open up tremendous capabilities where you may want to show data across your environments in one SAPUI5 application. Or, you could pull data from a very broad SAP instance landscape by implementing SAP Gateway in a hub-based pattern and then getting Cloud Connector to channel calls to multiple Gateway instances which can then channel calls every SAP Backend in your landscape. And of course you can retrieve your non-SAP data too if you have exposed it to the internet in some manner.

Having solved this problem I see much potential – hope you do too.

 

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

Leave a Reply