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:
Hi,
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
DATA:
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.
ENDLOOP.
LOOP AT lt_transp INTO ls_transp.
CREATE OBJECT l_factory.
TRY.
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
ENDIF.
CONTINUE.
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
ENDIF.
CONTINUE.
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
ENDIF.
CONTINUE.
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
ENDIF.
CONTINUE.
ENDTRY.
TRY.
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
ENDTRY.
CONCATENATE p_chkv
ls_transp-strkorr
sy-datum
sy-uzeit
ls_transp-as4user
ls_transp-name_last
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 ).
TRY.
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.)
ENDTRY.
l_ext_field_list-package_name = abap_true.
l_ext_field_list-exc_validity = abap_true.
TRY.
l_result_access->get_findings(
EXPORTING
i_ext_field_list = l_ext_field_list
IMPORTING
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.)
ENDTRY.
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 ) }|.
CONCATENATE l_msg
ls_transp-strkorr
ls_transp-as4user
ls_transp-name_last
INTO l_msg
SEPARATED BY space.
gs_atc_msg-msg = l_msg.
APPEND gs_atc_msg TO gt_atc_msg.
ENDLOOP.
"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.
ENDLOOP.
ENDMETHOD.
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?
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.
Cheers
Baerbel
Bärbel Winkler Do you have this in some public repository?
Pablo Costantini
Hi Pablo,
do you mean the code to trigger the ATC-checks or something else? If the former, all I can offer is the relevant code snippet explained in this blog post about triggering ATC-checks. The "surrounding code" in the program I have this in is not in any shape or form to be shared as I put it together "haphazardly" over the years, so it's not even "tidy code" let alone clean code!
Cheers
Bärbel
Hi Bärbel,
Thank you for your valuable blog, which helped us to understand the flow of the ATC process when we tried to display findings programmatically. we have used these ATC classes to get the details of findings. our requirement is to customise the output to show summarised/unified results when we run ATC checks for multiple transports.
could you please let me know where should I look at to find the structure for the display results. we are not using fm 'SATC_AC_DISPL_RESULT_BY_EXEC'. we have almost similar format though.
Thank you!
Asanka.
Hi Asanka,
I'm sorry but I won't be able to answer your question as I won't be back in the office with access to our system until mid-October. And even then, I'm not sure if I can provide more information than what is shown in the blog post.
Cheers
Bärbel
Thanks Bärbel. I understand. Sometimes there are limitations.
Cheers,
Thanks for the blog again.
Asanka
If you want to perform checks for specific objects or requests for transport requests you can also use these functions.
However, in my case I also needed to find the priority of the error, and I solved this by directly accessing the ATC tables (in this case cds)