WRITE_FILE_TO_PATH.ABAP

mail@pastecode.io avatar
unknown
abap
a year ago
14 kB
0
Indexable
Never
class-methods WRITE_FILE_TO_PATH
    importing
      value(IV_FILEPATH) type STRING
      value(IV_OVERWRITE) type ABAP_BOOL default ABAP_FALSE
      value(IV_FILE_LENGTH) type I optional
      value(IT_DATA) type SOLIX_TAB
    returning
      value(RV_UPLOADED) type ABAP_BOOL
    raising
      ZCX_GENERIC .


method write_file_to_path.

    constants: lc_msg_id           type syst-msgid value '00',
               lc_msg_no           type syst-msgno value '001',
               lc_logical_filename type filename-fileintern value 'EHS_FTAPPL_2'. " same as that used in CG3Y

    clear rv_uploaded.

    data(lv_filepath) = iv_filepath.
    data(lt_data) = it_data.
    data(lv_overwrite) = iv_overwrite.
    data(lv_file_length) = iv_file_length.
    data(lo_helper) = new lcl_helper( ).

* ---- input parameter validation ---- *
    if lv_filepath is initial or lt_data is initial.
      data(lv_msg) = conv bapi_msg( 'Mandatory input missing: Filepath/Binary data' ).
      raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
    endif.

    if lt_data is not initial and lv_file_length is initial.
      lv_msg = 'Please supply length of binary data for accurate conversion'.
      raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
    endif.

* ---- Compute filepath type ---- *
    data(lv_file_path_type) = cond #( when lv_filepath ca gc_path_sep-windows then gc_path_sep-windows
                                      when lv_filepath ca gc_path_sep-unix then gc_path_sep-unix ).

    " Note on .bin : => file extension does not matter. The data is stored in binary format anyways...
    " ...and can be directly converted to target extension while reading/downoading
    case lv_file_path_type.
      when gc_path_sep-windows.
        if sy-batch = abap_true.
          lv_msg = 'GUI not available in background mode'.
          raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
        endif.
        if strlen( lv_filepath ) = 1 and lv_filepath = gc_path_sep-windows. " indicator that the default filepath is to be used
          lv_filepath = cond #( when lo_helper is bound then lo_helper->get_temp_file_path(
                                                               exporting
                                                                 iv_front_end  = abap_true ) ).
        endif.
        if lv_filepath is not initial.
          " to-do: validate filename/path
          if lo_helper->validate_file_path(
               exporting
                 iv_filepath          = lv_filepath
                 iv_contains_filename = abap_true ).
            if lv_file_length is initial.
              lv_file_length = xstrlen( cl_bcs_convert=>solix_to_xstring(
                                          exporting
                                            it_solix = lt_data ) ).
            endif.
            cl_gui_frontend_services=>gui_download(
              exporting
                bin_filesize              = cond #( when lv_file_length is not initial then lv_file_length )
                filename                  = lv_filepath
                filetype                  = conv #( gc_extension-bin )
                confirm_overwrite         = lv_overwrite
              importing
                filelength                = data(lv_bytes_transferred)
              changing
                data_tab                  = lt_data
              exceptions
                file_write_error          = 1
                no_batch                  = 2
                gui_refuse_filetransfer   = 3
                invalid_type              = 4
                no_authority              = 5
                unknown_error             = 6
                header_not_allowed        = 7
                separator_not_allowed     = 8
                filesize_not_allowed      = 9
                header_too_long           = 10
                dp_error_create           = 11
                dp_error_send             = 12
                dp_error_write            = 13
                unknown_dp_error          = 14
                access_denied             = 15
                dp_out_of_memory          = 16
                disk_full                 = 17
                dp_timeout                = 18
                file_not_found            = 19
                dataprovider_exception    = 20
                control_flush_error       = 21
                not_supported_by_gui      = 22
                error_no_gui              = 23
                others                    = 24 ).
            if sy-subrc <> 0.
              message id sy-msgid type sy-msgty number sy-msgno
                         with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 into lv_msg.
              raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
            else.
              message |{ lv_bytes_transferred } bytes transferred to { lv_filepath }| type 'S'.
              " verify data upload...
              rv_uploaded = check_file_exists( iv_filepath = lv_filepath ).
            endif.
          else.
            lv_msg = 'Invalid filepath specified'.
            raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
          endif.
        endif.
      when gc_path_sep-unix.
* ---- set default app server filepath if not supplied ---- *
        if strlen( lv_filepath ) = 1 and lv_filepath = gc_path_sep-unix. " indicator that the default filepath is to be used
          lv_filepath = cond #( when lo_helper is bound then lo_helper->get_temp_file_path(
                                                               exporting
                                                                 iv_app_server  = abap_true ) ).
        endif.

        if lv_filepath is not initial.
* ---- check the authority to write the file to the application server ---- *
*    if iv_with_auth_check = abap_true.
          data(lv_program) = conv authb-program( sy-cprog ).
          data(lv_auth_filename) = conv authb-filename( lv_filepath ).
          call function 'AUTHORITY_CHECK_DATASET'
            exporting
              program          = lv_program  " ABAP program in which access occurs
              activity         = sabc_act_write " Access Type (See Function Documentation)
              filename         = lv_auth_filename " File name
            exceptions
              no_authority     = 1        " You are not authorized for this access
              activity_unknown = 2        " Access type unknown
              others           = 3.
          if sy-subrc <> 0.
            case sy-subrc.
              when 1.
                lv_msg = 'Not authorised to write the file to app server'.
              when others.
                lv_msg = 'File open error'.
            endcase.
            raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
          endif.
*    endif.

* ---- validate physical filename against logical filename ---- *
          call function 'FILE_VALIDATE_NAME'
            exporting
              logical_filename           = lc_logical_filename
            changing
              physical_filename          = lv_filepath
            exceptions
              logical_filename_not_found = 1
              validation_failed          = 2
              others                     = 3.
          if sy-subrc <> 0.
            message id sy-msgid type sy-msgty number sy-msgno
              with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 into lv_msg.
            raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
          endif.

* ---- handle overwriting ---- *
          if lv_overwrite = abap_false
            and check_file_exists( exporting iv_filepath = lv_filepath ). " generic file existence check, works for both frontend and app server
            lv_msg = 'File already exists on app server.'.  " overwriting not requested
            raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
          elseif lv_overwrite = abap_true
            and check_file_exists( exporting iv_filepath = lv_filepath ).
            try.
                delete dataset lv_filepath.  " overwriting requested, so delete the file first if it exists
                " alternative "open dataset dset for appending..."
              catch cx_sy_file_authority into data(lox_file_authority).
                lv_msg = lox_file_authority->get_text( ).
                raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
              catch cx_sy_file_open into data(lox_file_open).
                lv_msg = lox_file_open->get_text( ).
                raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
            endtry.
          endif.

          try.
              " open the dataset for writing
              open dataset lv_filepath for output in binary mode.
              if sy-subrc = 0.
                try.
                    " lines and file length are required for exact calculation of size of last line of data
                    data(lv_lines) = lines( lt_data ).

                    " In case of direct ct_data input, file length is supplied by user since...
                    " ...it's not possible to calculate exact binary file size from lt_data alone
                    " But if its not supplied last resort is to compute length using binary tab...
                    if lv_file_length is initial.
                      lv_file_length = xstrlen( cl_bcs_convert=>solix_to_xstring(
                                                 exporting
                                                   it_solix = lt_data ) ).
                    endif.

                    loop at lt_data assigning field-symbol(<ls_data>).
                      " this part....
                      " ...is required since the size of data in the last line may be less than 255 bytes
                      " If we do not pass the exact binary length, some non-existant empty data is pushed...
                      " ...which renders the file unreadable/uncompatible
                      data(lv_max_len) = xstrlen( <ls_data>-line ). " max length of each line
                      if lv_lines gt 1.
                        if sy-tabix = lv_lines. " calculate length of last line...
                          data(lv_len) = lv_file_length - ( lv_max_len * ( lv_lines - 1 ) ).
                          " last line size = total file size - totat length of previous lines
                        else.
                          lv_len = lv_max_len.  " all other lines = max line length
                        endif.
                      else.
                        lv_len = lv_file_length.  " lines = 1 means entire filedata is one line
                      endif.
                      " end of this part
                      " write binary data to dataset line by line
                      transfer <ls_data>-line to lv_filepath length lv_len.  " pass exact length of data to be transfered
                      clear lv_len.
                    endloop.

                    try.
                        " close the dataset after writing
                        close dataset lv_filepath.

                        message |{ lv_file_length } bytes transferred to { lv_filepath }| type 'S'.

                        " verify data upload...
                        rv_uploaded = check_file_exists( iv_filepath = lv_filepath ).
                      catch cx_sy_file_close into data(lox_file_close).
                        lv_msg = lox_file_close->get_text( ).
                        raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
                    endtry.
                  catch cx_sy_file_io into data(lox_file_io).
                    lv_msg = lox_file_io->get_text( ).
                    raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
                  catch cx_sy_file_open_mode into data(lox_file_open_mode).
                    lv_msg = lox_file_open_mode->get_text( ).
                    raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
                  catch cx_sy_file_access_error into data(lox_file_access_error).
                    lv_msg = lox_file_access_error->get_text( ).
                    raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
                endtry.
              else.
                lv_msg = 'File open error'.
                raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
              endif.
            catch cx_sy_file_authority into lox_file_authority.
              lv_msg = lox_file_authority->get_text( ).
              raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
            catch cx_sy_file_open into lox_file_open.
              lv_msg = lox_file_open->get_text( ).
              raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
            catch cx_sy_too_many_files into data(lox_too_many_files).
              lv_msg = lox_too_many_files->get_text( ).
              raise exception type zcx_generic message id lc_msg_id type 'E' number lc_msg_no with lv_msg.
          endtry.

        endif.
      when others.
    endcase.
  endmethod.


 if lv_data is not initial.
      data(lv_file_length) = xstrlen( lv_data ).
      ev_file_length = lv_file_length.
      data(lt_data) = cl_bcs_convert=>xstring_to_solix(
                            exporting
                              iv_xstring = lv_data ).
      rt_data = lt_data.

      if lv_filepath is not initial.
        try.
            data(lv_uploaded) = write_file_to_path(
              exporting
                iv_filepath    = lv_filepath        " Path of file to write to on frontend or app server
                iv_file_length = lv_file_length     " Size of binary data
                it_data        = lt_data ).         " Binary Data
          catch zcx_generic into data(lox_generic). " Generic Exception Class
            message lox_generic type 'S' display like 'E'.
        endtry.
      endif.
    endif.