cancel
Showing results for 
Search instead for 
Did you mean: 

How to properly implement the method CREATE_STREAM for File Upload in the SAP Gateway Server

Former Member
0 Kudos

Good morning everyone,

It is me again with another issue where I NEED the help of all the GREAT EXPERTS here. For a couple of days now, I have been trying to  familiarize myself with File Upload and Download as Service from the SAP Gateway OData. I read a couple of BLOGS here and from there I was able to gather some knowledges. Thank you SO MUCH to those AUTHORS, without their inputs, I would have been completely LOST. This particular blog was HELPFUL =>

There the author used the UPDATE_STREAM method to UPLOAD the file to the SAP Back-end system. I used his approach and it worked fine. Now I was curious and wanted to know if I could try to implement the CREATE_STREAM method, which is actually the one to use to CREATE(UPLOAD) a new file. Before that I created a transparent table named 'ZZUPLD' to store the uploaded files. Here is a screenshot of that table which has a total of 6 fields, where the most important are the FILENAME, MIMETYPE and VALUE

Now after creating the project in SEGW and inside it the Entity named File which was marked as MEDIA resource and has only ONE property in my case(the filename), I redefined the CREATE_STREAM method of the CLASS DPC_EXT according to all the blogs' documentations.

Below is my OWN implementation of the CREATE_STREAM

***************************************************************Code Begin*****************************************************************************************

method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM.
**try.
*CALL METHOD SUPER->/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM
*  EXPORTING
**    iv_entity_name          =
**    iv_entity_set_name      =
**    iv_source_name          =
*    IS_MEDIA_RESOURCE       =
**    it_key_tab              =
**    it_navigation_path      =
*    IV_SLUG                 =
**    io_tech_request_context =
**  importing
**    er_entity               =
*    .
** catch /iwbep/cx_mgw_busi_exception .
** catch /iwbep/cx_mgw_tech_exception .
**endtry.

" This method actually performs the File UPLOAD process. The file which is inserted in the HTTP POST request
" has to be saved in the transparent table, predefined for it. The table name is 'ZZUPLD' and it consists of
" 6 fields: MANDT, FILENAME, SYDATE, SYTIME, VALUE, MIMETYPE. Except from the MANDT field which is filled
"AUTOMATICALLY the others 5 fields MUST be filled here accordingly

  data: ls_file type ZZUPLD
        .

"Now fill the ls_file accordingly

  ls_file-filename = iv_slug.
  ls_file-sydate   = sy-datum.
  ls_file-sytime   = sy-uzeit.
  ls_file-mimetype = is_media_resource-mime_type.
  ls_file-value    = is_media_resource-value.

  "Fill the export parameter er_entity accordingly
  copy_data_to_ref(
    exporting
      is_data = ls_file
    changing
      cr_data = er_entity )
      .



  "Now add the file to the transparent table

  MODIFY zzupld from ls_file.



   endmethod.


***************************************************************Code End*****************************************************************************************


Here is the screenshot of the UPLOAD process using SAP Gateway Client tool




Here is a screenshot of HTTP Response with an ERROR message EVEN THOUGH the FILE is actually UPLOADED  and STORED in the ZZUPLD table .




Here is the screenshot where I used the GET_STREAM method to DOWNLOAD the previous UPLOADED file and as you can see the FILE was really UPLOADED to the Back-end



Can someone PLEASE tell me why the HTTP Response of the UPLOAD REQUEST(CREATE_STREAM) has an ERROR even though the file is SUCCESSFULLY uploaded? I think it is related to my implementation of CREATE_STREAM. Thanks in ADVANCE for you SUPPORT and have a GREAT day

Accepted Solutions (1)

Accepted Solutions (1)

ugurkaya
Active Participant

Hey Grace,

Your File entity looks like having only 1 attribute? is that all. If yes, you can not pass all those fields to er_entity. Looks like, you are trying to show values from table in your entity structure, that may be the error.

If no, can you show me the fields of er_entity (and file entity structure) in the end of the create_stream method. I want to make sure you are filling all the required fields of ls_file ( returning entity ).

Also could you put screenshot of the error from /N/IWFND/ERROR_LOG transaction.

Regards

Ugur.

Former Member
0 Kudos

Good afternoon Ugur,

first of all THANK YOU for your response. You are RIGHT, my Entity has only ONE property which is named 'filename' from type STRING. You are also RIGHT about the value of er_entity. I ADJUSTED my code concerning that area => "Fill the export parameter er_entity accordingly
  copy_data_to_ref(
    exporting
      is_data = iv_slug
    changing
      cr_data = er_entity )
      .


The file is still UPLOADED but I get an ERROR in the HTTP Response. Here is the screenshot

What can be the PROBLEM in the HTTP Response of the HTTP Upload REQUEST. I strongly believe it is RELATED to the CREATE_STREAM method. Thanks AGAIN for the SUPPORT

ugurkaya
Active Participant
0 Kudos

Hey Grace,

This error may be related to your get_entity method of your file entity.

Could you put a break point and check if everything is going fine when fileset_get_entity is called after create stream method.

Normal output should be like the screenshot below. You can see get_entity method is called and output is returned to the post request.

In my case i do not return the file stream though, i just return the content url of the image.

Former Member
0 Kudos

Good morning Ugur,

I did NOT redefine the method FILESET_GET_ENTITY of the CLASS DPC_EXT. I did not know it was NECESSARY for the CREATE_STREAM method. What code should I implement in FILESET_GET_ENTITY? Since my entity type has ONLY  ONE property, which is the filename(type STRING), I guess it is that filename I must retrieve and RETURN as ER_ENTITY of FILESET_GET_ENTITY. PLEASE can I have a look at your codes for CREATE_STREAM and FILESET_GET_ENTITY. A screenshot would be NICE. This would HELP me to identify my ERROR. I would also like to know WHY your URI for the HTTP GET request looks so different. I thought the URI for HTTP GET REQUEST must look like this

=> /sap/opu/odata/SAP/ZDEMO_FILE_SRV/FileSet('TS.jpg')/$value

You have at the end of your URI 'AttachmentSet' while I have '$value'. Do you mind explaining to me why yours is different? Thanks in advance Ugur for your GREAT SUPPORT

ugurkaya
Active Participant
0 Kudos

Hello Grace,

There are couple of differences between our methods.

You are streaming the the file with $value, I only get the content url with get_entity method. Since i save the file to the content server on my "create_stream" method I just need the url of the file to show to user. However, you keep the content of the file in a table and you are streaming it back every time when requested. I do not prefer doing it that way

In my get_entity method, basically I retrieve the content url, file name and some other required fields.

You can find attached related codes, but i may not be very useful for your scenario.

get_entity: https://www.dropbox.com/s/cqb8bffjjmm6yui/get_entity.txt?dl=1

create_stream : https://www.dropbox.com/s/axfv0gxistnqf7h/create_stream.txt?dl=1

By the way:

'Z_CRM_UI5_ONERI_FILE_UPLOAD' -> is a custom function to save any attachment to the content server in sap crm module for my case.

'Z_CRM_UI5_ONERI_FILE_READ' -> is a custom function to read attachments on a service order in sap crm module for my case.

If you cant see the attachments, leave me a message.

Regards.

Ugur.

Former Member
0 Kudos

Hi Ugur,

THANKS A LOT for your codes. I would have a look at them and let you KNOW if I was able to solve my HTTP Response Problem. Through discussions I really learn a WHOLE LOT here and I am GRATEFUL. I wish you a VERY NICE week end in ADVANCE 

Former Member
0 Kudos

Good afternoon Ugar,

I redefined the method 'FILESET_GET_ENTITY' in DPC_EXT. Currently it is EMPTY since I don't know EXACTLY what to write there but my CREATE_STREAM method DOES NOT function anymore, by that I mean it is  NO MORE called and the FILE is NOT UPLOADED. This is DEFINITELY related to the fact that I redefined the method 'FILESET_GET_ENTITY'. Humm now I am really CONFUSED. I have read other blogs but I was UNABLE to find out the SOLUTION to my problem. Initially my UPLOAD process with CREATE_STREAM was "WORKING" and my 'FILESET_GET_ENTITY' was NOT redefined in DPC_EXT, my problem was ONLY the HTTP Response then. But since I redefined 'FILESET_GET_ENTITY' even though currently EMPTY I can no longer UPLOAD my FILE with CREATE_STREAM. Can someone PLEASE help me out? Why MUST I redefine 'FILESET_GET_ENTITY' when UPLOADING the file with CREATE_STREAM? In which way are these two methods related?  How MUST I implement 'FILESET_GET_ENTITY' given the fact that my entity type as ONLY ONE property which is the FILENAME of type STRING. PLEASE I need HELP .

ugurkaya
Active Participant
0 Kudos

Hey Grace,

Did you activate your dpc_ext class, and check for syntax errors. In your FILESET_GET_ENTITY method you should be checking if the requested file is uploaded to your table. FileName is your key attribute here, you can simply check for the database record and return the filename as your entity.

If you want to use get_entity method and assuming that you have passed key parameters from create stream method, you can use something similar:


DATA: ls_key_tab LIKE LINE OF it_key_tab,

          lv_filename type string.


READ TABLE it_key_tab INTO ls_key_tab WITH KEY name = 'Filename'.

if sy-subrc eq 0.

   lv_filename = ls_key_tab-value.

endif.

* check if record exists.

* if yes

er_entity-filename = lv_filename.


Also, you can just return created entity from create_stream method like that, without calling get_entity method if you are confused.



DATA: begin of ls_file,

            filename type string,

          end of ls_file.


****

**

* create stream operations

**

****

*

*


ls_file-filename = iv_slug.


copy_data_to_ref( EXPORTING is_data = ls_file

                           CHANGING  cr_data = er_entity ).


**

*



You can delete your redefinition if you prefer second option.


Basically you return the created file entity on the response, to avoid internal server error for the file upload request.


I hope this helps.


Regards


Ugur


Former Member
0 Kudos

Good morning Ugur,

you are really NICE, THANK YOU so much for your SUPPORT . The UPLOAD request using CREATE_STREAM is "WORKING". I did NOT do anything, may be it was my system on Friday. But I still have an ERROR in the HTTP RESPONSE of the POST request. I am currently reading a document concerning MEDIA RESOURCE. Inside that document it is said that we have to REDEFINE the method DEFINE of MPC_EXT and point out which PROPERTY of the ENTITY TYPE contains the MIME TYPE. In my case I ONLY have the FILENAME of type STRING as the entity property. So the big question is since my entity type does not have a MIME TYPE property which code must I implement in the method DEFINE? In the HTTP Request the MIME TYPE should be included. Do you have an idea how I can retrieve the MIME TYPE from the HTTP POST REQUEST and set it in the method DEFINE. They said it is VERY IMPORTANT to set the MIME TYPE in the method DEFINE, otherwise the framework would generate an ERROR even though the FILE is UPLOADED and this is what happens here. THANKS in ADVANCE

ugurkaya
Active Participant
0 Kudos

Morning Grace,

You can follow these steps to set mime type.

First you need to add mimetype field to your file entity structure, after that regenerate your service.

Go to mpc_ext class and right click redefine "DEFINE" method, put the following code:

Be careful with the entity & property names, case sensitive.


DATA: lo_entity   TYPE REF TO /iwbep/if_mgw_odata_entity_typ,

           lo_property TYPE REF TO /iwbep/if_mgw_odata_property.

     

     super->define( ).

     lo_entity = model->get_entity_type( iv_entity_name = 'File' ).

     IF lo_entity IS BOUND.

       lo_property = lo_entity->get_property( iv_property_name = 'Mimetype' ).

       lo_property->set_as_content_type( ).

     ENDIF.

Important thing is, you should be passing the mimetype with filename field in your response entity after create stream method. Otherwise you may not be able to set the content type since it will be empty value.

You might want to have a look to following links for better understanding.

Regards

Ugur.

Former Member
0 Kudos

Hi Ugur,

Thanks for the links. I am trying ALL your suggestions now. Even though I have NOT yet found the SOLUTION, the exchange with you HELPED me a WHOLE lot. I was able to learn NEW THINGS. THANK YOU . I believe with all your HINTS I would find the SOLUTION. I would let you know as soon as I am DONE, hopefully it might help others also. Have a WONDERFUL day and stay BLESSED

Former Member

In our UPLOAD and DOWNLOAD processes we will use SAP Gateway OData service. The FILES will be STORED in a database table which has to be DEFINED.

In our case the database table will have a total of 6 FIELDS: MANDT, FILENAME, SYDATE, SYTIME, VALUE, MIMETYPE. See their data types in the corresponding

screenshot. The following procedure consists of SEVEN(7) steps and OTHERS blogs here HELPED me to make it,THANKS to all the AUTHORS particularly to Ugur Kaya

1- Create the database table which will store the FILES(see screenshot)

2- Create your project in SEGW and create your entity type named 'File'. You can choose ANOTHER name. This entity type has to be marked as MEDIA since we

want to DEAL with a media resource(binary data such as IMAGE, VIDEO etc..). See the screenshot.

  When you define an entity type as a MEDIA type that entity type should have a PROPERTY that will store the MIME TYPE of your media resource.

  In this scenario the entity type named 'File' will have TWO properties of type STRING: FileName(Type String), MIMEType(Type String).

The property 'FileName' is a KEY property in this scenario. See screenshot

3- You have to SPECIFY which of the Entity type properties stores the MIME TYPE. This is done through the REDEFINITION of the method 'DEFINE' of the CLASS

MPC_EXT

method DEFINE.

"When an entity type as been defined as 'media' we have to define in this DEFINE method which property

" of the entity type stores the MIME Type. It is a MUST to do

  data : lo_entity_type type ref to /iwbep/if_mgw_odata_entity_typ,

         lo_property type ref to  /iwbep/if_mgw_odata_property.

"Call the super-class method FIRST!!!

super->define( ).

"Retrieve the entity type and store it in   lo_entity_type

lo_entity_type = model->get_entity_type( 'File' ).

  IF lo_entity_type is bound .

    "Retrieve the corresponding entity type property and store it in lo_property

    lo_property = lo_entity_type->get_property( 'MIMEType' ).

    "Now set lo_property as MIME TYPE using the method 'set_as_content_type( )'

    lo_property->set_as_content_type( ).

  ENDIF.

  endmethod.

4- Here we will REDEFINE the method 'FILESET_GET_ENTITY'. This method will be CALLED from the method CREATE_STREAM after the FILE has been SUCCESSFULLY

   UPLOADED to the database table. The method CREATE_STREAM which will be REDEFINED BELOW, performs the UPLOAD of the FILE to the database table and

    it will pass the FileName and the MIMEType to the method FILESET_GET_ENTITY, which will fill the export parameter 'ER_ENTITY'

   method fileset_get_entity.

**try.

*CALL METHOD SUPER->FILESET_GET_ENTITY

*  EXPORTING

*    IV_ENTITY_NAME          =

*    IV_ENTITY_SET_NAME      =

*    IV_SOURCE_NAME          =

*    IT_KEY_TAB              =

**    io_request_object       =

**    io_tech_request_context =

*    IT_NAVIGATION_PATH      =

**  importing

**    er_entity               =

**    es_response_context     =

*    .

** catch /iwbep/cx_mgw_busi_exception .

** catch /iwbep/cx_mgw_tech_exception .

**endtry.

"The main idea is to return the FileName and the MIMEType. This method will be called in the CREATE_STREAM

" method. The necessary parameters will be passed through the IT_KEY_TAB

  data : lv_filename type string,

         lv_mimetype type string.

  field-symbols <lf_keys> type /iwbep/s_mgw_name_value_pair.

  data ls_file type zzupld.

  "Read the the parameters from the it_key_tab

  read table it_key_tab assigning <lf_keys> with key name = 'FileName'.

  if sy-subrc = 0.

  lv_filename = <lf_keys>-value.

  endif.

  read table it_key_tab assigning <lf_keys> with key name = 'MIMEType'.

  if sy-subrc = 0.

  lv_mimetype = <lf_keys>-value.

  endif.

"First be assured that lv_filename and lv_mimetype are NOT initial

if  lv_filename is not initial and lv_mimetype is not initial .

    "Now read read the entry from the database table

   select single * from zzupld into ls_file  where filename = lv_filename and mimetype = lv_mimetype .

     if sy-subrc = 0.

       "The entry was FOUND, now you can fill the er_entity accordingly

       er_entity-filename = ls_file-filename.

       er_entity-mimetype = ls_file-mimetype.

     endif.

endif.

  endmethod.

5- REDEFINE the method CREATE_STREAM. This is the method that performs the UPLOAD PROCESS.

    method /iwbep/if_mgw_appl_srv_runtime~create_stream.

**try.

*CALL METHOD SUPER->/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM

*  EXPORTING

**    iv_entity_name          =

**    iv_entity_set_name      =

**    iv_source_name          =

*    IS_MEDIA_RESOURCE       =

**    it_key_tab              =

**    it_navigation_path      =

*    IV_SLUG                 =

**    io_tech_request_context =

**  importing

**    er_entity               =

*    .

** catch /iwbep/cx_mgw_busi_exception .

** catch /iwbep/cx_mgw_tech_exception .

**endtry.

" This method actually performs the File UPLOAD process. The file which is inserted in the HTTP POST request

" has to be saved in the transparent table, predefined for it. The table name is 'ZZUPLD' and it consists of

" 6 fields: MANDT, FILENAME, SYDATE, SYTIME, VALUE, MIMETYPE. Except from the MANDT field which is filled

"AUTOMATICALLY the others 5 fields MUST be filled here accordingly

data: ls_file type zzupld

       .

"---------------------------New data definitions-----------------------------------------------------------

data : ls_key_tab type /iwbep/s_mgw_name_value_pair,

       lt_key_tab type /iwbep/t_mgw_name_value_pair,

       BEGIN OF ls_filemetadata,

                 filename type string,

                 mimetype type string,

       END OF ls_filemetadata.

"---------------------------New data definitions-----------------------------------------------------------

"Now fill the ls_file accordingly

ls_file-filename = iv_slug.

ls_file-sydate   = sy-datum.

ls_file-sytime   = sy-uzeit.

ls_file-mimetype = is_media_resource-mime_type.

ls_file-value    = is_media_resource-value.

"---------------------------New codes-------------------------------------------------------------

"The idea is to fill the lt_key_tab with filename and mimetype using ls_key_tab

ls_key_tab-name = 'FileName'.

ls_key_tab-value = iv_slug.

append ls_key_tab to lt_key_tab.

ls_key_tab-name = 'MIMEType'.

ls_key_tab-value = is_media_resource-mime_type.

append ls_key_tab to lt_key_tab.

"File the structure that will stores the file metadata: filename, mime type

move iv_slug to ls_filemetadata-filename.

move is_media_resource-mime_type to ls_filemetadata-mimetype.

"---------------------------New codes-------------------------------------------------------------

"Now add the file to the transparent table

modify zzupld from ls_file.

if sy-subrc = 0.

  "Now call the FILESET_GET_ENTITY method

   fileset_get_entity(

     exporting

       iv_entity_name          = iv_entity_name

       iv_entity_set_name      =  iv_entity_set_name

       iv_source_name          = iv_source_name

       it_key_tab              = lt_key_tab

*       io_request_object       =

*       io_tech_request_context =

       it_navigation_path      = it_navigation_path

     importing

       er_entity               =  ls_filemetadata

*       es_response_context     =

     )  .

  "Fill the export parameter er_entity accordingly

copy_data_to_ref(

   exporting

     is_data = ls_filemetadata

   changing

     cr_data = er_entity )

     .

endif.

  endmethod.

6- REDEFINE the method GET_STREAM to perform the FILE DOWNLOAD

method /iwbep/if_mgw_appl_srv_runtime~get_stream.

**try.

*CALL METHOD SUPER->/IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM

**  exporting

**    iv_entity_name          =

**    iv_entity_set_name      =

**    iv_source_name          =

**    it_key_tab              =

**    it_navigation_path      =

**    io_tech_request_context =

**  importing

**    er_stream               =

**    es_response_context     =

*    .

** catch /iwbep/cx_mgw_busi_exception .

** catch /iwbep/cx_mgw_tech_exception .

**endtry.

"The GET_STREAM method is used for File Download from the SAP Back-end system to an external target repository

"Define the necessary data first. "UPLD" stands for UPLOAD

data: ls_stream type ty_s_media_resource,

       ls_upld type zzupld,

       lv_filename type char30.

field-symbols <fs_key> like line of it_key_tab.

  read table it_key_tab assigning <fs_key> index 1.

"Read the file name from the field symbol and store it into the local variable

  lv_filename = <fs_key>-value.

  "Now select the corresponding file from the database to perform the DOWNLOAD

  select single * from zzupld into ls_upld where filename = lv_filename .

  if ls_upld is not initial.

   "Now copy the binary data

   ls_stream-value = ls_upld-value.

   ls_stream-mime_type = ls_upld-mimetype.

   copy_data_to_ref(

                      exporting

                        is_data = ls_stream

                      changing

                        cr_data = er_stream

                     ) .

  endif.

  endmethod.

7- You can test your Service for UPLOAD and DOWNLOAD using Gateway Client tool.

   For the HTTP POST request, you have to add a header parameter named 'slug' and its value. This parameter will contain the FILENAME. Please see the

   screenshot

  

   For the DOWNLOAD, which is a HTTP GET request, you have to add '/$value' after given the FILENAME inside the Entityset 'FileSet'. Please see

   the Screenshot.

  The code is definitely NOT optimal, but it WORKS and I will improve it LATER, for now I am just HAPPY I understood it. Thanks Ugur, you are the BEST

  

Answers (2)

Answers (2)

0 Kudos

What if I am trying to upload from postman, can anyone guide me through this?

abdulkalam_a
Participant
0 Kudos

Thank you so much all for the very useful blog..!!