Skip to Content
Technical Articles

How to trigger multiple ATC-checks in one go

Encouraged by the feedback I received in the Coffee Corner, here is a 2nd Q&A turned into a blog post. I decided to do this in this particular case because I didn’t just get a very simple solution to my question but because it also examplifies how helpful the SAP community can be – and even in possibly record time!

About a year ago and in preparation for our upgrade to the SAP HANA database I started to look into the SCI/ATC options and how to make good use of them. One thing which was bugging me was that I wasn’t able to find anything about how to call the ATC from a report program and provide the results in one go for multiple objects/transports. So, I posted a question about just that in Answers on Feb. 22, 2017 at 8:06 in the morning my time In Germany. Imagine my surprise, when I got a notification about a response from Axel Jebens  within an hour – at 8:48 to be precise! – which was short and to the point:


There is an object-oriented API which you can use to create an own program based on class CL_SATC_API_FACTORY. Please check out the example program RSATC_API_USAGE_EXAMPLE. There is a remote-enabled API and example program, too. See program RSATC_API_REMOTE_USAGE_EXAMPLE.

Hope it helps!

This turned out to be exactly what I was looking for and it was easy to implement as well! I checked out the sample code, copied it into a test-program, tweaked some of the hard-coded values to fit our own data (i.e. the program name or transport ID) and checked the results of this prototyping.

The next step was to add the logic – with some more tweaks – into a program I already had which lets me select transport-requests by various criteria. I basically just needed to add another routine to call the API from within a loop through the table with the already selected transports. I also decided to ignore any errors along the way (apart from a wrong check-variant) as I’m mainly using this for spot checks. I already had the program running each morning to send an email with a list of currently open transport-requests so I added the ATC-summary to that email. The ATC-information just includes the transport-ID and the number of findings encountered, but the details can be looked at as needed via Tcode ATC in the dev-system. So, as time allows, I can now use that email to do some spot checks on e.g. transports showing many findings. I had this up and running around noon.

Here is how the tweaked code looks like:

METHOD trigger_atc.

  "Local definitions for ATC API calls
    l_factory            TYPE REF TO cl_satc_api_factory,
    l_object_set         TYPE REF TO if_satc_object_set,
    l_variant            TYPE REF TO if_satc_check_variant,
    l_configuration      TYPE REF TO if_satc_run_configuration,
    l_controller         TYPE REF TO if_satc_run_controller,
    l_result_access      TYPE REF TO if_satc_result_access,
    l_findings           TYPE scit_rest,
    l_findings_extension TYPE satc_ci_findings_extension,
    l_ext_field_list     TYPE satc_ci_finding_ext_field_list,
    l_msg                TYPE string,
    l_cx                 TYPE REF TO cx_root,
    l_description(128)   TYPE c.

  "Table for transport numbers
  DATA: BEGIN OF ls_transp,
          strkorr LIKE e070ctv-strkorr,
          as4user     LIKE e070ctv-as4user,
          name_last   LIKE user_addr-name_last,
        END   OF ls_transp.

  DATA: lt_transp LIKE TABLE OF ls_transp.

  DATA: ls_dl_objects LIKE LINE OF gt_dl_objects.

  "Restrict to relevant ABAP-objects (via sel-screen input)
  LOOP AT gt_dl_objects INTO ls_dl_objects WHERE pgmid  IN s_pgmid
                                             AND object IN s_obj_em
                                             AND trkorr IN s_cts.
    "Add transport-ID to internal table for summary listing in email
    ls_transp-strkorr = ls_dl_objects-strkorr.
    ls_transp-as4user = ls_dl_objects-as4user.
    ls_transp-name_last = ls_dl_objects-name_last.
    COLLECT ls_transp INTO lt_transp.

  LOOP AT lt_transp INTO ls_transp.

    CREATE OBJECT l_factory.
        l_object_set = cl_satc_object_set_factory=>create_for_transport( i_transport = ls_transp-strkorr ).
      CATCH cx_satc_empty_object_set INTO l_cx.
        IF sy-batch EQ gc_x.
          MESSAGE i000(38) WITH 'Processing of transport'(E03) ls_transp-strkorr 'ended with error:'(e04).
          MESSAGE l_cx TYPE 'I'. " Object set contains no checkable objects
      CATCH cx_satc_not_found INTO l_cx.
        IF sy-batch EQ gc_x.
          MESSAGE i000(38) WITH 'Processing of transport'(E03) ls_transp-strkorr 'ended with error:'(e04).
          MESSAGE l_cx TYPE 'I'. " Object set contains no checkable objects
      CATCH cx_satc_invalid_argument INTO l_cx.
        IF sy-batch EQ gc_x.
          MESSAGE i000(38) WITH 'Processing of transport'(E03) ls_transp-strkorr 'ended with error:'(e04).
          MESSAGE l_cx TYPE 'I'. " Object set contains no checkable objects
      CATCH cx_satc_failure INTO l_cx.
        IF sy-batch EQ gc_x.
          MESSAGE i000(38) WITH 'Processing of transport'(E03) ls_transp-strkorr 'ended with error:'(e04).
          MESSAGE l_cx TYPE 'I'. " Object set contains no checkable objects

        l_variant = l_factory->get_repository( )->load_ci_check_variant( i_name = p_chkv ).
      CATCH cx_satc_not_found INTO l_cx.
        MESSAGE l_cx TYPE 'E'. " Specified Code Inspector variant was not found

    CONCATENATE p_chkv
           INTO l_description
      SEPARATED BY ' - '.

    l_configuration = l_factory->create_run_config_with_chk_var(
      i_object_set    = l_object_set
      i_check_variant = l_variant
      i_description   = l_description ).

    l_configuration->set_pragma_option( i_option = if_satc_ac_project_constants=>c_mode_fndng_xmptd_in_code-show_as_open ).

    l_controller = l_factory->create_run_controller( l_configuration ).

        l_controller->run( IMPORTING e_result_access = l_result_access ).
      CATCH cx_satc_failure INTO l_cx.
        MESSAGE l_cx TYPE 'E'. " ATC check run failed (no authorization, etc.)

    l_ext_field_list-package_name = abap_true.
    l_ext_field_list-exc_validity = abap_true.

            i_ext_field_list     = l_ext_field_list
            e_findings           = l_findings
            e_findings_extension = l_findings_extension ).
      CATCH cx_satc_failure INTO l_cx.
        MESSAGE l_cx TYPE 'E'. " Result access failed (no authorization, etc.)

    l_msg = 'Number of Findings / Extensions: &1 / &2'(I01).
    REPLACE ALL OCCURRENCES OF '&1' IN l_msg WITH |{ lines( l_findings ) }|.
    REPLACE ALL OCCURRENCES OF '&2' IN l_msg WITH |{ lines( l_findings_extension ) }|.

           INTO l_msg
      SEPARATED BY space.

    gs_atc_msg-msg = l_msg.
    APPEND gs_atc_msg TO gt_atc_msg.


  "Add the ATC-summary to the simple list
  SKIP 1.
  WRITE: / 'Summary of ATC-findings:'(i02).

  LOOP AT gt_atc_msg INTO gs_atc_msg.
    WRITE: / gs_atc_msg-msg.


So, from asking the question to having a working solution implemented took not even 5 hours in this case. Which is quite a quick turnaround as far as I can tell!

Do you have similar examples of where the community came through this quickly?

You must be Logged on to comment or reply to a post.
  • I'm pretty sure I have a similar example of fast "customer service" on SCN 🙂 but it's somewhere in the archives under the previous profile. Most of my new "questions" these days are the complaints about the website. 🙂

    Thank you for posting this! We're just starting to look at better ways to organize our work and I'm pretty sure ATC check will be a part of it. So this will be very useful.

  • Here is an example where being able to execute ATC-checks "in bulk" came in very handy during our project to do ATC-checks via a central system and moving towards blocking on transport release:

    Once I had created the baseline in the ATC-system and set up a central check variant, I defined another daily job for my transport-selection program, looking at currently still modifiably transports and triggering the new central check for them. I then checked the ATC-results on a daily basis and used the information to tweak things like the message priorities for the central check variants as needed. The daily results showed clear progress with more and more findings ending up with priority 3 instead of 1 or 2 as intended:

    This example is also described in Setting up a central ATC-system – Part 3: Tweaking the settings to our liking.