Object Services Attachments using UploadCollection
The purpose of this blog is to provide one of the methods of handling Object Services Attachments in SAPUI5 applications and their OData services – focusing on reusable service utility structures and class methods.
I had been working with many custom applications that required showing and uploading attachments that go into Business Object Services Attachments. As I couldn’t find any comprehensive post on this topic, I thought of sharing something which I think as optimal way of handling such attachments.
The generic object services offer functions that are available in various SAP applications. These services are around a specific Business Object. Example of Business Objects in SAP include purchase orders, contracts, customers, etc. Here in this document we are going to focus on ‘Attachments’ which is one of the object services.
All the application services requiring object service attachments should include an entity of below type as part of their model. An attachment is identified with a composite key of Object ID, Object Type, Object Category and Document ID.
For example the list of object services attachments to a purchase requisition 12099353 are shown below:
The document ID is the combination of SOFD and SOOD table keys (<SOFDK><SOODK>). For example the first attachment above could be uniquely identified by the following key: Object ID: 0012099353; Object Type: BUS2105; Object Category: BO; Document ID: FOL38000000000004EXT43000000005537.
The entity for attachments is to be marked as ‘Media Type’
The model provider extension class should redefine DEFINE method to handle this Media Type entity.
The three main methods GET_ENTITYSET (attachment list), GET_STREAM and CREATE_STREAM are implemented in a utility class which is expected to be reused from each service requiring object services attachments.
This method would retrieve the list of attachments for a business object. As we already saw a business object is identified with the combination of Object ID, Object Type and Object Category. These would be available as part of keys / navigation source keys.
I don’t prefer to copy paste the ABAP code but would give high level flow.
- Use the method READ_LINKS_OF_OBJECTS of class CL_BINARY_RELATION to read the links of the objects (ET_LINKS_A)
- The field INSTID_B in the above table represents Document ID of each attachment link.
- As we saw this document id is in the structure <SOFDK><SOODK>, you can further query the table SOOD to fetch information like file extension, created by, created on, etc.
As the user would have the list of attachments already appearing in the UploadCollection and chooses an entry, this method should have the Document ID which is the key to get the attachment content.
- Read the Document ID from the keys
- Use the FM SO_DOCUMENT_READ_API1 to retrieve the document content
- Use the FM SCMS_BINARY_TO_XSTRING to convert the hex content to raw string
- Use the FM SDOK_MIMETYPE_GET to derive the Mime Type from the extension. The extension would be available in the field OBJ_TYPE of the structure DOCUMENT_DATA from the FM SO_DOCUMENT_READ_API1
- The ER_ENTITY should be populated using COPY_DATA_TO_REF utility method with a structure having fields MIME_TYPE and VALUE (binary content). It is better to use the type /iwbep/cl_mgw_abs_data=>ty_s_media_resource for this purpose.
The Object ID, Object Type and Object Category are passed from UI as part of request headers. We will see the UI part later in this document. The below code snippet shows how these information from request headers can be retrieved in the service implementation:
The main inputs for creating the attachment are:
- File content – IS_MEDIA_RESOURCE-VALUE
- File Name – IV_SLUG
- Business Object – (Structure SIBFLPORB: combination of object id, object type and object category)
The high level steps are as below:
- Use FM SO_FOLDER_ROOT_ID_GET with region as ‘B’ to get the FOLDER_ID
- Use FM TRINT_FILE_GET_EXTENSION to get the extension from the file name
- Use FM SCMS_XSTRING_TO_BINARY to convert the file content to binary
- Use FM SO_SOLIXTAB_TO_SOLITAB to convert binary (SOLIXTAB) to SOLITAB
- Use FM SO_OBJECT_INSERT to create the document object
- Use method CREATE_LINK of class CL_BINARY_RELATION or FM BINARY_RELATION_CREATE to link the document attachment and business object
- Don’t forget to return the entity (ER_ENTITY) using COPY_DATA_TO_REF utility method
The ‘ToAttachments’ is a navigation property of my main business object entity. The formatter function formatImageURL is given below. Remember the GET_ENTITYSET (attachment list) would return all these parts as explained earlier.
Create / Upload Attachments
Upload Collection – View
In the Init method of the controller, set the upload url for the collection
On the change event handler, set the security token in the header. Also optionally set the thumb-nail icon for the item being added:
You need to call upload method of the UploadCollection control as the instantUpload is turned off. Here the sequence of steps I used are:
- Create the business object first
- In the success handler of create method, read the created object id (e.g. Purchase Req.)
- Set the object id, object type, object category in a local JSON Model, which would be set as header parameters of the request (See below)
In the ‘Before Upload Starts’ event handler, set the file name and optionally the header parameters to be passed to the CREATE_STREAM method.
These header parameters should be added to whitelist in neo-app.json for the purpose of testing from Web IDE environment.
Refer to Graham Robinson’s SAUG 2017 presentation on Building Gateway Services for details on implementing the re-usable gateway service implementation classes.
Hope this blog (my first one) useful to you. Please register your questions and suggestions below. Thanks.