SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Creating a DMS attachment with SAPUI5

Introduction

This blog will guide you through the process of uploading a DMS document via a SICF service (REST). This blog will only feature the essentials. So, no error handling or anything of that sort.

Following steps will be taken to create and test such a service:

  1. Creating the web service in SAP Backend
    1. Creating the ZIF_REST Interface.
    2. Creating a Handler Class
    3. Creating the class for a POST Request
    4. Creating a node in transaction SICF
  2. Creating the SAPUI5 frontend
    1. Creating a new project
  3. Testing the service with SAPUI5 frontend

1. Creating the web service in SAP Backend

1.1. Creating the ZIF_REST Interface.

To start off with, let’s create an interface in ‘SE24’ (if it doesn’t exist yet) which we will use for almost all classes in this guide. The interface consists of two methods, one for the request and one for the response.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Add the attributes ‘RESPONSE‘ and ‘REQUEST‘ to the interface.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

The method ‘SET_RESPONSE’ has an importing parameter ‘IS_DATA’ with the ‘XSTRING’ type. Make sure you activate the interface.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

1.2. Creating a Handler Class

Go to ‘SE24’ and create a new class called ‘ZCL_TEST_DMS_ATTACHMENT. Select the tab ‘Interfaces’ and add interface ‘IF_HTTP_EXTENSION’.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Go back to the tab ‘Methods’ and you’ll see a method has been added. Add another method called ‘GET_REST’.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Add the following parameters to the method ‘GET_REST’.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Copy the following code to your method ‘IF_HTTP_EXTENSION~HANDLE_REQUEST’.

It will execute the ‘GET_REST’ method to get the class we want to execute to get or process the data.

METHOD IF_HTTP_EXTENSION~HANDLE_REQUEST.

***************************************************************************
” VARIABLES
***************************************************************************
DATA: LO_REST TYPE REF TO ZIF_REST.
DATA: LV_REASON TYPE STRING.
DATA: LO_INVALID_METHOD TYPE REF TO CX_ROOT.

***************************************************************************
” GET THE CLASS WE WANT TO EXECUTE
***************************************************************************
TRY.

LO_REST ?= GET_REST( IO_SERVER = SERVER ).

***************************************************************************
” EXECUTE THE CLASS
***************************************************************************
LO_REST->HANDLE_REQUEST( ).

***************************************************************************
” CATCH IF IT PRODUCES ERRORS
***************************************************************************
CATCH CX_ROOT INTO LO_INVALID_METHOD.

LV_REASON = LO_INVALID_METHOD->GET_TEXT( ).
SERVER->RESPONSE->SET_STATUS( CODE = 400 ” Bad Request
REASON = LV_REASON ).

ENDTRY.

ENDMETHOD.​

This method will first check what type of request we’re dealing with (GET, PUT, POST, … etc.). It will then append the name to the base class name. So, if a POST request is executed, the name of the class it will execute is ‘ZCL_TEST_DMS_ATTACHMENT_POST’.

METHOD GET_REST.

***************************************************************************
” VARIABLES
***************************************************************************
DATA: LV_CLASSNAME TYPE SEOCLSNAME.
DATA: LV_METHOD TYPE STRING.
DATA: LV_MESSAGE TYPE TEXT255.

***************************************************************************
” REQUEST TYPE (GET, POST, … ETC) AND APPEND IT TO GET THE CLASS NAME
***************************************************************************
LV_METHOD = IO_SERVER->REQUEST->GET_HEADER_FIELD( ‘~request_method’ ).
CONCATENATE ‘ZCL_TEST_DMS_ATTACHMENT_’ LV_METHOD INTO LV_CLASSNAME.

***************************************************************************
” RETURN THE CLASS TO IF_HTTP_EXTENSION~HANDLE_REQUEST
***************************************************************************
TRY.
CREATE OBJECT EO_REST
TYPE (LV_CLASSNAME)
EXPORTING
IO_REQUEST = IO_SERVER->REQUEST
IO_RESPONSE = IO_SERVER->RESPONSE.

***************************************************************************
” CATCH ERRORS
***************************************************************************
CATCH CX_SY_CREATE_OBJECT_ERROR.
LV_MESSAGE = ‘Method ”&” not supported'(001).
ENDTRY.

ENDMETHOD.

1.3. Creating the class for a POST Request

Go to ‘SE24’ and create a new class ‘ZCL_TEST_DMS_ATTACHMENT_POST’ and add interface ‘ZIF_REST’.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Your class will now have the first two methods below. Add a new method: ‘CONSTRUCTOR’.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Add the following parameters to ‘CONSTRUCTOR’. This will instantiate the class when called upon.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Open method ‘HANDLE_REQUEST’. This method will be executed from the handler class (‘ZCL_TEST_DMS_ATTACHMENT’).

METHOD ZIF_REST~HANDLE_REQUEST.

**************************************************************************************
” TYPES
**************************************************************************************
TYPES: BEGIN OF TYPE_FILE,
NAME TYPE STRING,
TYPE TYPE STRING,
OBJECT TYPE CHAR30,
OBJTYPE TYPE DOKOB,
DESCR TYPE STRING,
DOCTYPE TYPE DOKAR,
HEXCONT TYPE XSTRING,
END OF TYPE_FILE.

**************************************************************************************
” VARIABLES AND OTHERS
**************************************************************************************
“Tables
DATA: LT_OBJECTLINKS TYPE TABLE OF BAPI_DOC_DRAD.
DATA: LT_OBJECTDESCR TYPE TABLE OF BAPI_DOC_DRAT.
DATA: LT_OBJECTFILES TYPE TABLE OF BAPI_DOC_FILES2.
DATA LT_SOLIX_TAB TYPE TABLE OF SOLIX-LINE.

“Structures
DATA: LS_FILE TYPE TYPE_FILE.
DATA: LS_DOCDATA TYPE BAPI_DOC_DRAW2.
DATA: LS_OBJECTLINK TYPE BAPI_DOC_DRAD.
DATA: LS_OBJECTDESCR TYPE BAPI_DOC_DRAT.
DATA: LS_OBJECTFILE TYPE BAPI_DOC_FILES2.
DATA: LS_SOLIX TYPE SOLIX-LINE.

“Variables
DATA: LV_REQUEST_JSON_BODY TYPE STRING.
DATA: LV_QMNUM TYPE QMNUM.
DATA: LV_EQUNR TYPE EQUNR.
DATA: LV_TPLNR TYPE TPLNR.
DATA: LV_DOCNUMBER TYPE DOKNR.
DATA: LV_OUTPUT_LENGTH TYPE I.
DATA: LV_FILENAME TYPE STRING.

“Objects
DATA: LR_JSON_DESERIALIZER TYPE REF TO CL_TREX_JSON_DESERIALIZER.

CREATE OBJECT LR_JSON_DESERIALIZER.

**************************************************************************************
” GET JSON DATA FROM POST REQUEST
**************************************************************************************
LV_REQUEST_JSON_BODY = ME->ZIF_REST~REQUEST->GET_CDATA( ).

**************************************************************************************
” CONVERT JSON STRING TO ABAP STRUCTURE
**************************************************************************************
LR_JSON_DESERIALIZER->DESERIALIZE(
EXPORTING
JSON = LV_REQUEST_JSON_BODY
IMPORTING
ABAP = LS_FILE ).

**************************************************************************************
” CONVERT HEX CONTENT TO BINARY
**************************************************************************************
LV_OUTPUT_LENGTH = XSTRLEN( LS_FILE-HEXCONT ).

CALL FUNCTION ‘SCMS_XSTRING_TO_BINARY’
EXPORTING
BUFFER = LS_FILE-HEXCONT
IMPORTING
OUTPUT_LENGTH = LV_OUTPUT_LENGTH
TABLES
BINARY_TAB = LT_SOLIX_TAB.

**************************************************************************************
” CONVERT HEX STRING TO FILE AND SAVE IT IN TEMP FOLDER
**************************************************************************************
CONCATENATE ‘/usr/sap/’ LS_FILE-NAME ‘.’ LS_FILE-TYPE INTO LV_FILENAME.

IF NOT LT_SOLIX_TAB IS INITIAL.
OPEN DATASET LV_FILENAME FOR OUTPUT IN BINARY MODE.
LOOP AT LT_SOLIX_TAB INTO LS_SOLIX.
TRANSFER LS_SOLIX TO LV_FILENAME.
ENDLOOP.
CLOSE DATASET LV_FILENAME.
ENDIF.

**************************************************************************************
” SET VALUES OF LINK TABLES
**************************************************************************************
LS_DOCDATA-DOCUMENTTYPE = LS_FILE-DOCTYPE.
LS_DOCDATA-DOCUMENTVERSION = ’00’.
LS_DOCDATA-DOCUMENTPART = ‘000’.
LS_DOCDATA-LABORATORY = ‘001’.

LS_OBJECTDESCR-DESCRIPTION = LS_FILE-DESCR.
LS_OBJECTDESCR-LANGUAGE = ‘E’.
LS_OBJECTDESCR-LANGUAGE_ISO = ‘EN’.
APPEND LS_OBJECTDESCR TO LT_OBJECTDESCR.

LS_OBJECTFILE-ORIGINALTYPE = ‘001’.
LS_OBJECTFILE-STORAGECATEGORY = ‘DMS_C1_ST’.
LS_OBJECTFILE-SOURCEDATACARRIER = ‘SAP-SYSTEM’.
LS_OBJECTFILE-CREATED_BY = SY-UNAME.
LS_OBJECTFILE-DOCFILE = LV_FILENAME.
LS_OBJECTFILE-WSAPPLICATION = LS_FILE-TYPE.
APPEND LS_OBJECTFILE TO LT_OBJECTFILES.

LS_OBJECTLINK-OBJECTTYPE = LS_FILE-OBJTYPE.

“set object and object type when dealing with a notification
IF LS_FILE-OBJTYPE EQ ‘PMQMEL’.
UNPACK LS_FILE-OBJECT TO LV_QMNUM.
LS_OBJECTLINK-OBJECTKEY = LV_QMNUM.
ENDIF.

“set object and object type when dealing with an equipment
IF LS_FILE-OBJTYPE EQ ‘EQUI’.
UNPACK LS_FILE-OBJECT TO LV_EQUNR.
LS_OBJECTLINK-OBJECTKEY = LV_EQUNR.
ENDIF.

“set object and object type when dealing with a functional location
IF LS_FILE-OBJTYPE EQ ‘IFLOT’.
UNPACK LS_FILE-OBJECT TO LV_TPLNR.
LS_OBJECTLINK-OBJECTKEY = LV_TPLNR.
ENDIF.

APPEND LS_OBJECTLINK TO LT_OBJECTLINKS.

**************************************************************************************
” CREATE ATTACHMENT
**************************************************************************************
CALL FUNCTION ‘BAPI_DOCUMENT_CREATE2’
EXPORTING
DOCUMENTDATA = LS_DOCDATA
PF_FTP_DEST = ‘SAPFTPA’
PF_HTTP_DEST = ‘SAPHTTP’
IMPORTING
DOCUMENTNUMBER = LV_DOCNUMBER
TABLES
DOCUMENTDESCRIPTIONS = LT_OBJECTDESCR
OBJECTLINKS = LT_OBJECTLINKS
DOCUMENTFILES = LT_OBJECTFILES.

**************************************************************************************
” COMMIT
**************************************************************************************
COMMIT WORK.

ENDMETHOD.

For the sake of keeping it simple, I won’t be added code to method ‘SET_RESPONSE’. If you want more information on that, please read my other blog: http://sapabapcentral.blogspot.com/2018/06/writing-sicf-service.html

Now open method ‘CONSTRUCTOR’ and add following code. This method will instantiate the request and response when the class is called.

METHOD CONSTRUCTOR.

ME->ZIF_REST~RESPONSE = IO_RESPONSE.
ME->ZIF_REST~REQUEST = IO_REQUEST.

ENDMETHOD.

1.4. Creating a node in transaction SICF

Go to transaction ‘SICF’ and find a fitting node to which we can append a new one. In this case, we’ll opt for the already existing ‘ZREST’ node. Right click the node and add a new sub-element. We’ll name this node .

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Add a fittting description for the service node.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Navigate to the ‘Hander List’ tab and add the handler we created (‘ZCL_TEST_DMS_ATTACHMENT’).

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

For the sake of security, navigate to the tab ‘Logon Data‘. I’m just going to fill it like this, but you should add your own security to make it safe!!!

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Make sure you save the service properly.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Go back to the node list and right click the node you created and click ‘Activate service’.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

 

Click one of the two following buttons to active the node/service.

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

2. Creating the SAPUI5 frontend

2.1. Creating a new project

Create a new project with a view and controller called ‘Main‘ and add the code below.

Main.view.xml

This view contains:

  • 4 input fields (sap.m.Input)
    • Object number (QMNUM, EQUNR, TPLNR)
    • Object type (DOKOB)
    • Document type
    • Description
  • a file uploader (sap.ui.unified.FileUploader)
    • triggers the ‘onChange‘ event which will save the last selected file to a controller variable
  • a button (sap.m.Button)
    • triggers the ‘onConfirm‘ event which will upload the file to the SAP backend

<mvc:View controllerName=”FileUploader.controller.Main” xmlns:html=”http://www.w3.org/1999/xhtml” xmlns:mvc=”sap.ui.core.mvc” displayBlock=”true” xmlns=”sap.m” xmlns:f=”sap.ui.layout.form” xmlns:u=”sap.ui.unified”>
<App>
<pages>
<Page title=”File uploader”>
<content>
<VBox class=”sapUiSmallMargin”>
<Input type=”text” id=”idObjectNumber” placeholder=”object number” width=”225px” />
<Input type=”text” id=”idObjectType” placeholder=”object type” width=”225px” />
<Input type=”text” id=”idDocType” placeholder=”document type” width=”225px” />
<Input type=”text” id=”idDescription” placeholder=”description” width=”225px” />
<u:FileUploader
id=”fileUploader”
name=”myFileUpload”
width=”340px”
uploadUrl=”upload/”
tooltip=”Upload your file to the local server”
change=”onChange”/>
<Button
text=”Upload File”
press=”onConfirm”/>
</VBox>
</content>
</Page>
</pages>
</App>
</mvc:View>

Main.controller.js

This controller contains 6 methods:

  • onChange
    • passes the last selected file to a controller variable
  • onConfirm
    • is triggered when the upload button is pressed
    • executes the ‘uploadFile‘ method with the last selected file as a parameter
  • uploadFile
    • gets the data from the input fields
    • reads the file content as transforms it to hexadecimal string with the help of method ‘convertBinaryToHex‘
    • creates a stringied JSON object that is readable by the SAP backend with method ‘createJsonObjectForFileInfo‘
    • executes the ‘postAttachment‘ method
  • postAttachment
    • executes a POST request to the SAP backend
  • createJsonObjectForFileInfo
    • creates a stringied JSON object that is readable by the SAP backend
  • convertBinaryToHex
    • converts binary string to hexadecimal string

sap.ui.define([
“sap/ui/core/mvc/Controller”
], function(Controller) {
“use strict”;

return Controller.extend(“FileUploader.controller.Main”, {

onChange: function(oEvent) { // When the user selects a file
this.lastSelectedFile = oEvent.getParameter(“files”)[0];
},

onConfirm: function() { // When the user presses the upload button
this.uploadFile(this.lastSelectedFile);
},

uploadFile: function(file) {
var that = this;

var fileName = file.name.split(“.”)[0];
var fileType = file.name.split(“.”)[1];

var notificationNumber = this.byId(“idObjectNumber”).getValue();
var objectType = this.byId(“idObjectType”).getValue();
var docType = this.byId(“idDocType”).getValue();
var description = this.byId(“idDescription”).getValue();

var reader = new FileReader();

reader.onload = function(e) {
var raw = e.target.result;
var hexString = that.convertBinaryToHex(raw).toUpperCase();
var fileAsJsonString = that.createJsonObjectForFileInfo(fileName, fileType, hexString, docType, description, notificationNumber, objectType);
that.postAttachment(fileAsJsonString);
};

reader.onerror = function() {
sap.m.MessageToast.show(“error”);
};
reader.readAsArrayBuffer(file);
},

postAttachment: function(fileAsJsonString) {
var url = “http://xx.xxx.xx.xxx:8000/zrest/dms_attach?sap-client=400”;
var promise = new Promise(
function(resolve, reject) {

var xhttp = new XMLHttpRequest();
xhttp.open(“POST”, url, true);

xhttp.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
sap.m.MessageToast.show(“success”);
} else {
sap.m.MessageToast.show(“error”);
}
}
}

xhttp.send(fileAsJsonString);
});

return promise;
},

// create sap json string
createJsonObjectForFileInfo: function(fileName, fileType, hexString, docType, description, notificationNumber, objectType) {
return ‘{name:”‘ + fileName + ‘”,’ +
‘type:”‘ + fileType + ‘”,’ +
‘object:”‘ + notificationNumber + ‘”,’ +
‘objtype:”‘ + objectType + ‘”,’ +
‘descr:”‘ + description + ‘”,’ +
‘doctype:”‘ + docType + ‘”,’ +
‘hexcont:”‘ + hexString + ‘”}’;
},

convertBinaryToHex: function(buffer) {
return Array.prototype.map.call(new Uint8Array(buffer), x => (’00’ + x.toString(16)).slice(-2)).join(”);
}
});
});

3. Testing the service with SAPUI5 frontend

  1. Add an object (notification number, equipment number, functional location number)
  2. Choose the fitting object type (PMQMEL, EQUI, IFLOT)
  3. Choose a document type
  4. Add a fitting description
  5. Select a file
  6. Press the upload button

SAPUI5, ABAP Development, SAP Fiori, SAP NetWeaver

Leave a Reply

Your email address will not be published. Required fields are marked *