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: 
0 Kudos
287
The aBPM framework handles normally the REST calls between the browser and the Netweaver system by itself. The content for such calls will be set automatically and be send like the browser part of the aBPM framework has to do it. But in some specific situations the scenario developer knows that specific data must not be send because they are not relevant than they will be immediately cleared in one of the first lines of the callback implementation. One of this situation could be e.g. a result table that will be filled during every callback execution for a set of specific actions or drop down selections inside of a scenario implementation.
The effect by default is that every REST call has obsolete payload content that blows up the request size and needs additional browser-, network- and server-runtime for content that is fully irrelevant.

Inside of this article I will show you a simple trick how you can eliminate hugh obsolete payload content via some JavaScript functions before the payload will be send. This best practice will be embedded into the browser part of an ordinary aBPM scenario implementation.

Hint: Be aware that for other actions that needs such data the content of the REST payload should not be manipulated on browser side otherwise the aBPM framework would not be operate within normal parameters.

Prerequisites

Inside of my scenario I have a standalone generated scenario application that triggers different requests and shows mostly in a result table the matches for my filter options. But when I press the refresh button than the old result content will be send again to the Netweaver system. This is not necessary because the callback implementation clears first the old result table and executes than the internal select and set the new result content.


But for other actions inside of my application the existing content is relevant and should not be manipulated or removed.


Solution

To reduce the REST payload size and to increase the user acceptance for my application the solution is that for every specific action or drop down selection who triggers a REST call a JavaScript function clears my result table before the request will be send.

Realization

The realization of this solution can be embedded into the browser part of the scenario by adding JavaScript content into the UI5TabletViewRenderer that will be load at the start of an aBPM scenario.

Snippet to load and add the content of a file into the writer via helper classes inside UI5TabletViewRenderer:
try {
writer.append(JSFileReader.getFileStringByName(JSFileName.OVERDUE_INVOICE_EXECUTE_ACTION_CLEANUP));
} catch (IOException e) {
;
}

An example for a custom UI5TabletViewRenderer can be found here (point 2):

https://blogs.sap.com/2016/12/27/extend-abpm-with-pdf.js-a-pdf-viewer-that-runs-inside-different-bro...

The content of the JavaScript should looks like this:
sap.ui.core.Control.prototype.invalidateOverdueInvoiceTable = function(oEvent, oData) {
// console.log("invalidateOverdueInvoiceTable triggered");
// set OverdueInvoiceTable to an empty array
sap.ui.getCore().byId("formView").getModel("bo").oData.attributes.OverdueInvoiceTable.items = new Array();
// trigger the regular call of the FormController
sap.ui.getCore().byId("formView").getController().executeAction(oEvent, oData);
}

function switchEvent(objectReference, eventName) {
if (null != objectReference) {
// get references of old event
var existingOData = null;
var existingOListener = null;
if (eventName === 'press') {
existingOData = objectReference.mEventRegistry.press[0].oData;
existingOListener = objectReference.mEventRegistry.press[0].oListener;
} else if (eventName === 'change') {
existingOData = objectReference.mEventRegistry.change[0].oData;
existingOListener = objectReference.mEventRegistry.change[0].oListener;
}

// remove old event function and add new event function
if (eventName === 'press') {
objectReference.mEventRegistry = new Array();
objectReference.attachPress(existingOData,sap.ui.core.Control.prototype.invalidateOverdueInvoiceTable,existingOListener);
} else if (eventName === 'change') {
objectReference.mEventRegistry = new Array();
objectReference.attachChange(existingOData,sap.ui.core.Control.prototype.invalidateOverdueInvoiceTable,existingOListener);
}
}
}

function isAlphaNumeric(charCode) {
if ((charCode > 47 && charCode < 58) || // numeric (0-9)
(charCode > 64 && charCode < 91) || // upper alpha (A-Z)
(charCode > 96 && charCode < 123)) { // lower alpha (a-z)
return true;
}
return false;
}

function escapeTechnicalName(technicalName) {
if(null === technicalName) return null;
var tempTechnicalName = "";
for (i = 0; i < technicalName.length; i++) {
if(isAlphaNumeric(technicalName.charCodeAt(i))) {
tempTechnicalName = tempTechnicalName.concat(technicalName.charAt(i));
} else {
tempTechnicalName = tempTechnicalName.concat(technicalName.charCodeAt(i));
}
}
return tempTechnicalName;
}

function findUI5ControlIdViaUI5Registry(technicalName) {
var theEscapeTechnicalName = escapeTechnicalName(technicalName);
var regExpString = "[a-zA-Z]*_"+theEscapeTechnicalName+"\\d{0,100}";
regExp = new RegExp(regExpString);
// search in Element registry all potential UI5 controls
var ui5Controls = sap.ui.core.Element.registry.filter(checkElement);
if (ui5Controls.length === 1) {
// in case there is only one UI5 control return it
return ui5Controls[0].sId;
} else {
// in case more than one UI5 control was found check it in detail
for (i = 0; i < ui5Controls.length; i++) {
var matchResult = ui5Controls[i].sId.match(regExp);
// additionally check if there are addition parts inside of the sId after e.g. <tf_Test95GpsId025151> like <-content> or <-inner>, etc.
// if not deltaLengthCompare should be 0, hint: length calculation only possible if matchResult != null
var deltaLengthCompare = (matchResult != null) ? ui5Controls[i].sId.length - matchResult.toString().length : null;
if(matchResult != "undefined" && matchResult != null && deltaLengthCompare === 0) {
return ui5Controls[i].sId;
}
}
return null;
}
}

function checkElement(oElement, sID) {
if (!oElement.sId.startsWith("lb") && !oElement.sId.startsWith("__") && oElement.sId.match(regExp)) {
return true;
}
return false;
}

// input fields
var tf_GpsId = sap.ui.getCore().byId(findUI5ControlIdViaUI5Registry("Test_GpsId"));
switchEvent(tf_GpsId, "change");

// drop downs
var dd_SenderSID = sap.ui.getCore().byId(findUI5ControlIdViaUI5Registry("Test_SenderSID"));
switchEvent(dd_SenderSID, "change");
var dd_RelevantUser = sap.ui.getCore().byId(findUI5ControlIdViaUI5Registry("OverdueInvoice_RelevantUser"));
switchEvent(dd_RelevantUser, "change");
var dd_DomainSelection = sap.ui.getCore().byId(findUI5ControlIdViaUI5Registry("OverdueInvoice_DomainSelection"));
switchEvent(dd_DomainSelection, "change");

// buttons
var btn_Refresh = sap.ui.getCore().byId(findUI5ControlIdViaUI5Registry("Filter_RefreshButton"));
switchEvent(btn_Refresh, "press");

The trick here is that the JavaScript will be loaded and executed at the start of the scenario. And here the JavaScript implementation searchs the corresponding UI5 controls and change the default operations behind the relevant button, input field and drop downs to my own operation via function switchEvent().

Hint: The functions findUI5ControlIdViaUI5Registry(), escapeTechnicalName(), isAlphaNumeric() and checkElement() are helper functions that have only the task to find the correct UI5 control inside of the UI5 registry.

Important: The function findUI5ControlIdViaUI5Registry() use the original technical name of the aBPM scenario spread sheet.

Hint: For function switchEvent() the reference of the UI5 control is relevant and the information which event is to change (for input fields and drop downs event "change", for buttons "press")

The most interesting part of the JavaScript is inside of the prototype function invalidateOverdueInvoiceTable. Here the relevant table will be set to an empty array and than the original oEvent will be called. That means that this best practice does not change the default aBPM execution of the REST request it imbed more his own lines of code between the UI5 control and the aBPM browser side framework implementation.

Conclusion

After inserting this JavaScript coding every time when the button or the drop down selection will be triggered than the obsolete result table will be cleared before the request will be send to the Netweaver system.

This can be checked via DevTool inside Google Chrome and Notepad++ (with JSONFormatter) that the items list of the scenario BO of the result table is empty.