Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
Juwin
Active Contributor

As of today (Apr 10, 2024), SAP has not provided a method to debug application job on S/4HANA Public Cloud (related Question by @rammel ) or provided a method to pass parameters to the class via IF_OO_ADT_CLASSRUN (related Question by @fabianlupa answered by @horst_keller ). Below is a workaround method until SAP provides a way to do either of these options.

Every Class used in a Custom Job catalog uses interfaces IF_APJ_DT_EXEC_OBJECT and IF_APJ_RT_EXEC_OBJECT. IF_APJ_DT_EXEC_OBJECT~GET_PARAMETERS provides the parameter definition and IF_APJ_RT_EXEC_OBJECT~EXECUTE is responsible to receive the job parameters from the caller and execute the business logic.

The idea implemented here, is to create a wrapper to reuse this functionality to call the Execute method. The wrapper is created as a HTTP service so that it can be called from external parties to pass the required parameters.

So, first lets create a HTTP service. If you plan to use the plugin attached here, then please make sure to use the same name for HTTP service as ZSRV_ADT_PLUGIN_EXEC_JOBCLASS, since that name is used in the plugin.

2024-04-11 03_48_08-Doc1 - Word.png

Below is the code I used in the handler class. Please feel free to improvise this class, to have better authorization checks or validations according to your needs.

 

class zcl_adt_plugin_exec_jobclass definition
  public
  create public .

  public section.

    interfaces if_http_service_extension .
  protected section.
  private section.
endclass.



class zcl_adt_plugin_exec_jobclass implementation.
  method if_http_service_extension~handle_request.
    types: lty_char   type c length 100,
           ltyt_range type range of lty_char.
    data: lo_definition type ref to if_apj_dt_exec_object,
          lo_runtime    type ref to if_apj_rt_exec_object,
          lt_values     type if_apj_rt_exec_object=>tt_templ_val,
          begin of ls_value,
            param type string,
            range type ltyt_range,
          end of ls_value,
          lv_params type string.
    data(lt_form) = request->get_form_fields( ).
    loop at lt_form reference into data(lo_form).
      translate lo_form->name to upper case.
    endloop.
    read table lt_form into data(ls_form) with key name = 'CLASSNAME'.
    if sy-subrc eq 0.
      try.
          translate ls_form-value to upper case.
          create object lo_definition type (ls_form-value).
          create object lo_runtime type (ls_form-value).
          lo_definition->get_parameters( importing et_parameter_def = data(lt_params) ).
        catch cx_root into data(lo_root).
          response->set_text( |Class { ls_form-value } is invalid| ).
          response->set_status( 400 ).
          return.
      endtry.

      case request->get_method( ).
        when 'GET'.
          loop at lt_params into data(ls_param).
            lv_params = lv_params &&
                        cond #( when lv_params is not initial then ',' && cl_abap_char_utilities=>newline ) &&
                        |"{ ls_param-selname }":| &&
                        cond #( when ls_param-kind = 'S' then |[\{"SIGN":"I","OPTION":"EQ","LOW":"","HIGH":""\}]| else |""| ).
          endloop.
          lv_params = |\{{ cl_abap_char_utilities=>newline }{ lv_params }{ cl_abap_char_utilities=>newline }\}|.
          response->set_text( lv_params ).
        when 'POST'.
          try.
              data(lv_body) = request->get_text( ).
              loop at lt_params into ls_param.
                /ui2/cl_json=>deserialize( exporting json          = lv_body
                                                     name_mappings = value #( ( abap = cond #( when ls_param-kind = 'S' then 'RANGE' else 'PARAM' )
                                                                                json = ls_param-selname ) )
                                           changing  data          = ls_value ).
                if ls_param-kind = 'S'.
                  loop at ls_value-range into data(ls_rng).
                    append value #( selname = ls_param-selname sign = ls_rng-sign option = ls_rng-option low = ls_rng-low high = ls_rng-high ) to lt_values.
                  endloop.
                elseif ls_value-param is not initial.
                  append value #( selname = ls_param-selname low = ls_value-param ) to lt_values.
                endif.
                clear ls_value.
              endloop.
              lo_runtime->execute( lt_values ).
            catch cx_root.
              response->set_status( 400 ).
              return.
          endtry.
      endcase.
      response->set_content_type( 'application/json' ).
      response->set_status( 200 ).
    endif.
  endmethod.
endclass.

 

If you plan to use the custom plugin, then copy the plugin to the plugins folder of your Eclipse installation.

Juwin_1-1712762671534.png

Close the eclipse application and re-open it from command line using command eclipse.exe -clean, so that it re-reads the plugin folder.

Now, logon to SAP system via eclipse. In order to activate debugging request from plugin, please activate the following checkbox, for the ABAP Cloud Project.

Juwin_2-1712762812471.png

Open the custom Job Catalog related to the class that you would like to debug. Once you are the Job Catalog editor, open Run menu. If Eclipse found and installed the plugin correctly, then you should be able to see a new option saying "Run Job Class" as highlighted below. (This option will only be visible while on Job Catalog editor view)

Juwin_4-1712763000566.png

Now, open the related class and add a breakpoint in the Execute method of the Class.

Juwin_3-1712762921101.png

You can now go back to the Job Catalog Editor and select the option "Run Job Class". This will call the custom HTTP service that was created and which will internally create a JSON payload of the parameter list. It will then popup a dialog for you to edit the JSON.

Juwin_5-1712763138414.png

Modify the payload to pass values to each of the provided parameters in the JSON and hit OK.

Juwin_6-1712763184673.png

If you have setup everything right, then a new Debugger session will start and break at the breakpoint that you have set earlier.

Juwin_7-1712763240136.png

If you do not plan to use the plugin, other options may be to use tools like Postman or Restman to GET or POST, JSON payloads to the custom HTTP service.

Plugin can be downloaded from here.