Thursday, July 22, 2010

WebDynpro: Upload and Download file, part II (Download)

For download functionality we have the same process as for Upload. Download WD is created as separate WD component and is referred in the main WD application.

image

The download logic is as laid out in the diagram below. Event from download component is sent to the main WD component. Which then uses the assistance class to convert the structure into file layout. Then it calls the interface method in the download WD to send the file via the browser to the user for it to be saved.

image WD app component using Download WD component.

Download WD Component

This component will download any file that is selected into the internal table of the assistance class. The following has been created in this component.

image Layout output (V_DOWNLOAD)

image Layout design (V_DOWNLOAD)

image Components

image Context (V_DOWNLOAD & Component Controller)

There is one difference from the upload WD here, the context has been set to be as interface. The calling WD will the context with file information when it initialises the download WD.

image Events

image Methods in the main controller

At the component start up get the app name it is embedded in and create structure for mapping the file.
  1. METHOD wddoinit .
  2. wd_this->app_name = get_app_name( ).
  3. get_file_struc( ).
  4. get_date_format( ).

App name is retrieved here.
  1. METHOD get_app_name .
  2. DATA lo_api_componentcontroller TYPE REF TO if_wd_component.
  3. lo_api_componentcontroller = wd_this->wd_get_api( ).
  4. DATA lo_app TYPE REF TO if_wd_application.
  5. DATA lo_app_info TYPE REF TO if_wd_rr_application.
  6. lo_app = lo_api_componentcontroller->get_application( ).
  7. lo_app_info = lo_app->get_application_info( ).
  8. r_app_name = lo_app_info->get_name( ).

Retrieve the structure for the particular app and create dynamic structure in the assistance class.
  1. METHOD get_file_struc .
  2. DATA l_struc_name TYPE string.
  3. * Look for file structure in the lookup table
  4. SELECT SINGLE LKP_VALUE INTO l_struc_name
  5. FROM ZBC_LKP
  6. WHERE LKP_KEY = wd_this->app_name.
  7. IF sy-subrc IS NOT INITIAL.
  8. * get message manager
  9. DATA lo_api_controller TYPE REF TO if_wd_controller.
  10. DATA lo_message_manager TYPE REF TO if_wd_message_manager.
  11. lo_api_controller ?= wd_this->wd_get_api( ).
  12. lo_message_manager = lo_api_controller->get_message_manager( ).
  13. * report message
  14. lo_message_manager->report_error_message(
  15. message_text = 'No file structure defined for this app' ).
  16. * Send the assitance class the structure name
  17. TRY .
  18. wd_assist->set_structure_name( i_structure_name = l_struc_name ).
  19. CATCH zcx_library.
  20. * report message
  21. lo_message_manager->report_error_message(
  22. message_text = 'File format not supported'
  23. ).

If date format is specified then use it.
  1. METHOD get_date_format .
  2. DATA l_date_format TYPE string.
  3. * Look for date format in the lookup table
  4. SELECT SINGLE lkp_value INTO l_date_format
  5. FROM zbc_lkp
  6. WHERE lkp_key = wd_this->app_name.
  7. IF sy-subrc IS INITIAL.
  8. * Send the assitance class date format
  9. wd_assist->set_external_date_format( i_date_format = l_date_format ).

Now we come to user interactions. Assuming there is data that user wants to download, user will click the download button. Fire event for the App WD for data to be parsed and mapped into a file structure as per the application structure. Once the file structure is created then call the download method to push the file out. The file here is assumed to be tab delimited so that’s what the separator has been specified to.

image Action attached to the download button

  1. method ONACTIONDOWNLOAD_FILE .
  2. wd_comp_controller->start_download( ).
The component controller method start_download is called hence.
  1. METHOD START_DOWNLOAD.
  2. DATA lo_nd_file TYPE REF TO if_wd_context_node.
  3. DATA lo_el_file TYPE REF TO if_wd_context_element.
  4. DATA ls_file TYPE wd_this->element_file.
  5. * navigate from <CONTEXT> to <FILE> via lead selection
  6. lo_nd_file = wd_context->get_child_node( name = wd_this->wdctx_file ).
  7. * get element via lead selection
  8. lo_el_file = lo_nd_file->get_element( ).
  9. * get all declared attributes
  10. lo_el_file->get_static_attributes(
  11. IMPORTING
  12. static_attributes = ls_file ).
  13. * Calling WD should have provided file information
  14. IF ls_file IS INITIAL.
  15. throw_message( EXPORTING i_message = 'No file information provided'
  16. i_type = if_wd_message_manager=>co_type_error ).
  17. wd_this->file_name = ls_file-filename.
  18. wd_this->mime_type = ls_file-mimetype.
  19. * Fire event
  20. wd_this->fire_download_clicked_evt( ).
By this time the calling WD will receive the event and convert the data in to the file structure that it needs to send to. After this it will call the method DOWNLOAD_FILE in the download WD.
  1. METHOD download_file .
  2. DATA lt_data TYPE TABLE OF string.
  3. DATA l_data_string TYPE string.
  4. DATA l_data_xstring TYPE xstring.
  5. wd_assist->get_mapped_file( IMPORTING e_t_mapped_file = lt_data ).
  6. CONCATENATE LINES OF lt_data INTO l_data_string SEPARATED BY cl_abap_char_utilities=>newline.
  7. CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
  8. EXPORTING
  9. text = l_data_string
  10. IMPORTING
  11. buffer = l_data_xstring.
  12. cl_wd_runtime_services=>attach_file_to_response( i_filename = wd_this->file_name
  13. i_content = l_data_xstring
  14. i_mime_type = wd_this->mime_type ).

This covers the download WD component, in part III we will look at the usage of these 2 WD components.

Friday, July 02, 2010

WebDynpro: Upload and Download file, part I (Upload)

As with normal SAPGUI applications there are instances when there is need to write applications that interact with users with a file for sending and receiving data. You might want to upload a list of new Sales Orders or download a list of customers. Like the SAPGUI client there are UI elements here that provide functionality of file services. The approach taken here is to provide a generic file service that can be plugged into any WebDynpro component. Also work done earlier for upload and download in vanilla ABAP is reused.

imageWD app component using upload WD component

The WD components have been created sharing one assistance class. The WD components will be event driven. When the user clicks to upload/download the file, an event will be raised so that the WD App using the service can be alerted. The calling application can then use the assistance class to receive/send data.

image

Since the file has to be mapped to a structure, concept of a lookup table is used to decide what structure each application uses. At the initialisation of component a dynamic structure is created in the assistance class.

Assistance class

Assistance class will help the components to create the dynamic structure for each App. This will also map the file into the structure and vice versa. If the input file has a date then app can specify the date format of the input file to convert from. Here are the methods of the assistance class.

CONVERT_DATE2SAP Instance Method Private Convert the external date format to internal SAP date format
SET_EXTERNAL_DATE_FORMAT Instance Method Public Set the external date format to be used in file conversion
GET_MAPPED_FILE Instance Method Public Get the file content mapped in the structure
SET_STRUCTURE_NAME Instance Method Public Set the structure for which data needs to be mapped
CONVERT_STRUC2FILE Instance Method Public Converts structure into file
CONVERT_FILE2STRUC Instance Method Public Converts file into structure
  1. METHOD convert_date2sap.
  2. DATA l_o_type TYPE REF TO cl_abap_typedescr.
  3. * Get the type of the field
  4. l_o_type = cl_abap_typedescr=>describe_by_data( p_data = i_sap_field ).
  5. * For date type convert from DD.MM.YYYY to YYYYMMDD
  6. IF l_o_type->type_kind = cl_abap_typedescr=>typekind_date AND
  7. i_ext_field IS NOT INITIAL AND date_format IS NOT INITIAL.
  8. TRY.
  9. IF i_ext_field = '00.00.0000' . "Ingore 'zero' date.
  10. CLEAR e_sap_field.
  11. CALL METHOD cl_abap_datfm=>conv_date_ext_to_int
  12. EXPORTING
  13. im_datext = i_ext_field
  14. im_datfmdes = date_format
  15. IMPORTING
  16. ex_datint = e_sap_field.
  17. CATCH cx_abap_datfm_no_date cx_abap_datfm_invalid_date
  18. cx_abap_datfm_format_unknown cx_abap_datfm_ambiguous .
  19. e_sap_field = i_ext_field.
  20. e_sap_field = i_ext_field.

  1. METHOD SET_EXTERNAL_DATE_FORMAT.
  2. date_format = i_date_format.

  1. METHOD get_mapped_file.
  2. FIELD-SYMBOLS <lt_file_table> TYPE ANY TABLE.
  3. ASSIGN file_tab->* TO <lt_file_table>.
  4. e_t_mapped_file[] = <lt_file_table>.

  1. METHOD set_structure_name.
  2. DATA lo_type TYPE REF TO cl_abap_typedescr.
  3. DATA lo_tabletype TYPE REF TO cl_abap_tabledescr.
  4. CALL METHOD cl_abap_structdescr=>describe_by_name
  5. EXPORTING
  6. p_name = i_structure_name
  7. RECEIVING
  8. p_descr_ref = lo_type
  9. EXCEPTIONS
  10. type_not_found = 1
  11. OTHERS = 2.
  12. IF sy-subrc <> 0.
  13. RAISE EXCEPTION TYPE zcx_library
  14. EXPORTING
  15. textid = zcx_library=>incorrect_structure.
  16. o_struc_type ?= lo_type.
  17. CREATE DATA file_row TYPE HANDLE o_struc_type.
  18. TRY.
  19. CALL METHOD cl_abap_tabledescr=>create
  20. EXPORTING
  21. p_line_type = o_struc_type
  22. RECEIVING
  23. p_result = lo_tabletype.
  24. CATCH cx_sy_table_creation .
  25. RAISE EXCEPTION TYPE zcx_library
  26. EXPORTING
  27. textid = zcx_library=>incorrect_structure.
  28. CREATE DATA file_tab TYPE HANDLE lo_tabletype.
  29. * Structure mapped successfully

  1. METHOD convert_struc2file.
  2. l_struc TYPE REF TO data,
  3. l_o_datadescr TYPE REF TO cl_abap_datadescr,
  4. l_o_tabledescr TYPE REF TO cl_abap_tabledescr,
  5. l_t_fields TYPE string_table,
  6. l_s_fields TYPE string.
  7. DATA lt_dfies TYPE TABLE OF dfies.
  8. DATA lst_dfies TYPE dfies.
  9. DATA l_data_string TYPE string.
  10. DATA l_column_name TYPE string.
  11. <l_filecontent> TYPE ANY TABLE,
  12. <l_filerow> TYPE ANY,
  13. <l_field> TYPE ANY,
  14. <l_row> TYPE ANY,
  15. <l_table_content> TYPE table.
  16. ASSIGN file_row->* TO <l_row>.
  17. ASSIGN file_tab->* TO <l_table_content>.
  18. CLEAR <l_row>.
  19. CLEAR <l_table_content>.
  20. * Check structure mapping has happened first.
  21. IF o_struc_type IS INITIAL.
  22. RAISE EXCEPTION TYPE zcx_library
  23. EXPORTING
  24. textid = zcx_library=>no_structure_mapped.
  25. **********************************************************************
  26. CALL METHOD o_struc_type->get_ddic_field_list
  27. EXPORTING
  28. p_including_substructres = abap_true
  29. RECEIVING
  30. p_field_list = lt_dfies.
  31. * Add header.
  32. IF i_flag_header = abap_true.
  33. LOOP AT lt_dfies INTO lst_dfies.
  34. l_column_name = lst_dfies-scrtext_s.
  35. AT FIRST.
  36. CONCATENATE l_data_string l_column_name INTO l_data_string.
  37. CONCATENATE l_data_string lst_dfies-scrtext_s INTO l_data_string
  38. SEPARATED BY i_seperator.
  39. AT LAST.
  40. CONCATENATE l_data_string cl_abap_char_utilities=>newline INTO l_data_string.
  41. * add the content.
  42. LOOP AT i_t_data INTO <l_row>.
  43. WHILE sy-subrc IS INITIAL.
  44. ASSIGN COMPONENT sy-index OF STRUCTURE <l_row> TO <l_field>.
  45. IF sy-subrc IS NOT INITIAL.
  46. IF sy-index = 1.
  47. CONCATENATE l_data_string <l_field> INTO l_data_string.
  48. CONCATENATE l_data_string <l_field> INTO l_data_string
  49. SEPARATED BY i_seperator.
  50. CONCATENATE l_data_string cl_abap_char_utilities=>newline INTO l_data_string.
  51. **********************************************************************
  52. SPLIT l_data_string AT cl_abap_char_utilities=>newline INTO TABLE <l_table_content>.


  1. METHOD convert_file2struc.
  2. l_struc TYPE REF TO data,
  3. l_o_datadescr TYPE REF TO cl_abap_datadescr,
  4. l_o_tabledescr TYPE REF TO cl_abap_tabledescr,
  5. l_t_fields TYPE string_table,
  6. l_s_fields TYPE string.
  7. <l_filecontent> TYPE ANY TABLE,
  8. <l_filerow> TYPE ANY,
  9. <l_field> TYPE ANY,
  10. <l_row> TYPE ANY,
  11. <l_table_content> TYPE table.
  12. ASSIGN file_row->* TO <l_row>.
  13. ASSIGN file_tab->* TO <l_table_content>.
  14. CLEAR <l_row>.
  15. CLEAR <l_table_content>.
  16. * Check structure mapping has happened first.
  17. IF <l_row> IS NOT ASSIGNED.
  18. RAISE EXCEPTION TYPE zcx_library
  19. EXPORTING
  20. textid = zcx_library=>no_structure_mapped.
  21. * Take out the header
  22. DATA l_start TYPE i.
  23. IF i_flag_header = abap_true.
  24. l_start = 2.
  25. l_start = 1.
  26. LOOP AT i_t_file_data ASSIGNING <l_filerow> FROM l_start.
  27. IF i_seperator IS INITIAL. " File is same as structure
  28. <l_row> = <l_filecontent>.
  29. *---split based on the separator
  30. SPLIT <l_filerow> AT i_seperator INTO TABLE l_t_fields.
  31. LOOP AT l_t_fields INTO l_s_fields.
  32. ASSIGN COMPONENT sy-tabix OF STRUCTURE <l_row> TO <l_field>.
  33. * If external date format is mentioned then
  34. * convert file content into SAP format
  35. IF date_format IS NOT INITIAL.
  36. convert_date2sap( EXPORTING i_sap_field = <l_field>
  37. i_ext_field = l_s_fields
  38. IMPORTING e_sap_field = <l_field> ).
  39. <l_field> = l_s_fields.
  40. APPEND <l_row> TO <l_table_content>.

Upload WD Component

This component will upload any file that is selected into the internal table of the assistance class. The following has been created in this component.

image Layout output (V_UPLOAD)



image Layout design (V_UPLOAD)

image Components

imageContext (V_UPLOAD & Component Controller)

image Events

image Methods in the main controller

At the component start up get the app name it is embedded in and create structure for mapping the file.

  1. METHOD wddoinit .
  2. wd_this->app_name = get_app_name( ).
  3. get_file_struc( ).
  4. get_date_format( ).
App name is retrieved here.

  1. METHOD get_app_name .
  2. DATA lo_api_componentcontroller TYPE REF TO if_wd_component.
  3. lo_api_componentcontroller = wd_this->wd_get_api( ).
  4. DATA lo_app TYPE REF TO if_wd_application.
  5. DATA lo_app_info TYPE REF TO if_wd_rr_application.
  6. lo_app = lo_api_componentcontroller->get_application( ).
  7. lo_app_info = lo_app->get_application_info( ).
  8. r_app_name = lo_app_info->get_name( ).
Retrieve the structure for the particular app and create dynamic structure in the assistance class.

  1. METHOD get_file_struc .
  2. DATA l_struc_name TYPE string.
  3. * Look for file structure in the lookup table
  4. SELECT SINGLE LKP_VALUE INTO l_struc_name
  5. FROM ZBC_LKP
  6. WHERE LKP_KEY = wd_this->app_name.
  7. IF sy-subrc IS NOT INITIAL.
  8. * get message manager
  9. DATA lo_api_controller TYPE REF TO if_wd_controller.
  10. DATA lo_message_manager TYPE REF TO if_wd_message_manager.
  11. lo_api_controller ?= wd_this->wd_get_api( ).
  12. lo_message_manager = lo_api_controller->get_message_manager( ).
  13. * report message
  14. lo_message_manager->report_error_message(
  15. message_text = 'No file structure defined for this app' ).
  16. * Send the assitance class the structure name
  17. TRY .
  18. wd_assist->set_structure_name( i_structure_name = l_struc_name ).
  19. CATCH zcx_library.
  20. * report message
  21. lo_message_manager->report_error_message(
  22. message_text = 'File format not supported'
  23. ).
If date format is specified then use it.

  1. METHOD get_date_format .
  2. DATA l_date_format TYPE string.
  3. * Look for date format in the lookup table
  4. SELECT SINGLE lkp_value INTO l_date_format
  5. FROM zbc_lkp
  6. WHERE lkp_key = wd_this->app_name.
  7. IF sy-subrc IS INITIAL.
  8. * Send the assitance class date format
  9. wd_assist->set_external_date_format( i_date_format = l_date_format ).
Now we come to user interactions. User will select the file and click the upload button. The file will be parsed and mapped into internal table as per the application structure. Once the file is parsed into the internal table fire event for the App WD to receive the internal table. The file here is assumed to be tab delimited so that’s what the separator has been specified to.

image Action attached to the upload button


  1. METHOD onactionupload .
  2. wd_comp_controller->upload_file( ).
The component controller method upload_file is called hence.

  1. METHOD upload_file .
  2. DATA s_cont TYPE string.
  3. DATA convt TYPE REF TO cl_abap_conv_in_ce.
  4. DATA item_file TYPE xstringval.
  5. DATA t_table TYPE string_table.
  6. * get message manager
  7. DATA lo_api_controller TYPE REF TO if_wd_controller.
  8. DATA lo_message_manager TYPE REF TO if_wd_message_manager.
  9. lo_api_controller ?= wd_this->wd_get_api( ).
  10. lo_message_manager = lo_api_controller->get_message_manager( ).
  11. * ASSIGN mydate TO <target_fld>.
  12. DATA lo_nd_file TYPE REF TO if_wd_context_node.
  13. DATA lo_el_file TYPE REF TO if_wd_context_element.
  14. DATA lv_flag_header TYPE wdy_boolean.
  15. * navigate from <CONTEXT> to <FILE> via lead selection
  16. lo_nd_file = wd_context->get_child_node( name = wd_this->wdctx_file ).
  17. * get element via lead selection
  18. lo_el_file = lo_nd_file->get_element( ).
  19. * get File content
  20. lo_el_file->get_attribute(
  21. EXPORTING
  22. name = `FILE`
  23. IMPORTING
  24. value = item_file ).
  25. * get Header flag
  26. lo_el_file->get_attribute(
  27. EXPORTING
  28. name = `FLAG_HEADER`
  29. IMPORTING
  30. value = lv_flag_header ).
  31. TRY.
  32. convt = cl_abap_conv_in_ce=>create(
  33. encoding = 'UTF-8'
  34. input = item_file ).
  35. convt->read( IMPORTING data = s_cont ).
  36. CATCH cx_sy_conversion_codepage cx_sy_codepage_converter_init
  37. cx_parameter_invalid_type cx_parameter_invalid_range.
  38. * report message
  39. lo_message_manager->report_error_message(
  40. message_text = 'File format not supported').
  41. "Column headers
  42. SPLIT s_cont AT cl_abap_char_utilities=>cr_lf INTO TABLE t_table.
  43. * Send the file data
  44. TRY .
  45. wd_assist->convert_file2struc(
  46. i_t_file_data = t_table[]
  47. i_seperator = cl_abap_char_utilities=>horizontal_tab
  48. i_flag_header = lv_flag_header
  49. ).
  50. CATCH zcx_library.
  51. * report message
  52. lo_message_manager->report_error_message(
  53. message_text = 'Error processing file'
  54. ).
  55. wd_this->fire_upload_clicked_evt( ).
This covers the upload WD component, in part II we will look at download WD component.