Clean ABAP code ATC variant

Clean ABAP is the ABAP variant of the clean code principles. All background on clean ABAP code can be read in this blog.

This blog will explain how to upload the ABAP coding for the Clean ABAP ATC variant in your system and activate it.

Load ABAP Git code

To load the ATC variant code for clean ABAP you first need to install the ABAP Git code. Follow the instructions in this blog to do so. Simplest is the offline variant.

Download the ABAP clean code package

Now go to the Github code pal site for ABAP clean code and download the package:

Select the button Code and choose the option Download ZIP.

Upload the package

Now start the ABAP git that you loaded in your first step. Choose the option New Offline:

Give the repository a name and select a package:

Then push the button Create Offline Repo.

Now select Import Zip:

Import the file you downloaded in step 2 from the code pal site.

Next step is the Pull zip:

You might get a screen with differences. Do not select anything there, only press Ok.

Then wait until all the Y objects are pulled into the system. This might take 5 to 10 minutes.

Activating the SCI checks

Now start transaction SCI. Select menu option Code Inspector, Management of, Tests. Select all the newly load Y checks for Clean ABAP code:

Important now: Save them!

Now you can create a global SCI variant:

Select all the Clean code ABAP checks and save the variant:

You might get weird issues upon saving for other items, like for example missing CL_CI_CATEGORY_TOP. In that case, go to transaction SE16 -> look for table SCITESTS -> and look for CL_CI_CATEGORY_TOP if there is no entry. Enter the table SCITESTS and click "Create Entry", add CL_CI_CATEGORY_TOP entry and save.

Test and usage

Take a program you want check. Then select menu option Program, Check, ABAP Test Cockpit with….:

Select the ZCLEAN_ABAP SCI check we created above. Run the checks.

Results:

Tip: click on the blue line to jump to the Clean Code site exactly explaining about the issue.

Clean ABAP

Clean ABAP is the ABAP implementation of Clean code. Clean code is one of the key principles to adhere to when going Agile. Clean code is part of agile software development craftmanship. Read more on clean code in the original book.

Clean ABAP reference site

Clean ABAP is published and maintained on a dedicated Clean ABAP Github site.

The site itself is excellent and also has a special chapter how to best start with Clean ABAP.

The site is extensive and might be overwhelming. If you are a more traditional person, you can also read the SAP Press book on Clean ABAP code.

Blog on SAP site on clean ABAP can be found here.

Patterns and anti-patterns

The Clean ABAP explanation on the site contains both patterns (how you should do) and anti-patterns (how you should not do).

Anyhow the Clean ABAP principles are fully built on Object Orientation. That is a must.

Introducing Clean ABAP in your organization

Regardless if your organization is doing Agile or Waterfall development, or other development methodologies, Clean ABAP can be applied anyhow.

First step is to embrace the Clean ABAP as a principle direction. It will take time to get there. Not all developers will pick up as fast as you might want to. It also takes time to refactor old code to the Clean ABAP principles.

Discuss as developers as a team which part of the principles and improvements you want to pick up first. If you master a few, you can make it mandatory. Then take the next set. Some might pick up more at a higher pace. But keep the discussion going to improve and pick up every 2 weeks (sprint) at least 1 improvement item.

For a nice overview: read this SAP blog.

Peer review or pair programming: ATC variant

You can make the Clean ABAP code rules a part of your peer review or pair programming.

There is an ATC variant that can be uploaded that check for the clean ABAP code rules. Read this blog for instructions on how to do this.

Boy Scout rule

The boy scout rule is as follows: leave the place nicer than when you arrived, even though you didn’t make the mess. When you do this repetitively the world becomes a cleaner place.

This also applies to poor code: don’t just do your change, but take along some minor improvements as well. When you do this a couple of times, the poor code will improve every time towards good code.

But this principle you also need to embrace and explain. There might be unlucky situations where the clean up part might cause unexpected bug. This might happen in 0.01% of the cases. When it happens you might get resistance and pushback. But stand up for the principle, and simply correct the bug. It is worth it in the long run.

Humor

New input welcome, leave a comment!

What does the SAP abbreviation stand for?

  • SAP = Slow And Painful
  • SAP = Software Aus Pakistan
  • SAP = Shut up And Pay
  • SAP = Sanduhr Anschau Program
  • SAP = Schreibs Auf Papier
  • SAP = Suffer After Purchase
  • SAP = System against People
  • SAP = Start Applying Patches
  • SAP = Surrender and Pay
  • SAP = Sit and Panic
  • SAP = Severely Aged Programs
  • SAP = Submit (security bugs) and Pray
  • SAP = Sammelbecken Arbeitsloser Physiker -> German for Pool of Unemployed Physicists

Competence

Competence is limited, incompetence is unlimited
Below each level of incompetence there a next level of even worse incompetence
We don't need to remove the BigTruck button in STMS since nobody will be so stupid to start the ImportAll
Fundamental laws of stupidity:
1. Everybody underestimates the amount of stupid people
2. Stupidity is not related to any other characteristic of a person 
3. Stupid people damage others and themselves
4. Not-stupid people underestimate the damage of stupid people
5. Stupid people are more dangerous than smart criminals

Sending hyperlink in email with ABAP code

This blog will explain the ABAP code you can use to send an email from SAP system which is in HTML format including hyperlink.

Questions that will be answered in this blog are:

  • Which basis settings do I need to make for HTML mail format sending?
  • What code snippets can I re-use to send a hyperlink in an email from my custom ABAP program?

Basis settings for HTML mail

In order to be able to send an mail with a hyperlink the mail must have HTML format.

First check this table entry exists in table SXCONVERT2:

If not create it.

Now go to transaction SCOT and set the output format of RAW to HTM:

Save the settings.

ABAP code to mail hyperlink

The ABAP code to mail is as follows:

*&---------------------------------------------------------------------*
*& Report zemail_cl_bcs
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
  REPORT  zemail_cl_bcs.

  CONSTANTS:
    gc_subject TYPE so_obj_des VALUE 'ABAP Email with CL_BCS',
    gc_raw     TYPE char03 VALUE 'HTM'.

  DATA:
    gv_mlrec         TYPE so_obj_nam,
    gv_sent_to_all   TYPE os_boolean,
    gv_email         TYPE adr6-smtp_addr,
    gv_subject       TYPE so_obj_des,
    gv_text          TYPE bcsy_text,
    zls_text         TYPE soli,
    xhtml_string     TYPE xstring,
    gr_send_request  TYPE REF TO cl_bcs,
    gr_bcs_exception TYPE REF TO cx_bcs,
    gr_recipient     TYPE REF TO if_recipient_bcs,
    gr_sender        TYPE REF TO cl_sapuser_bcs,
    t_hex            TYPE solix_tab,
    gr_document      TYPE REF TO cl_document_bcs.

  DATA: zlv_longstring_message TYPE string.
  DATA: zlt_et_soli TYPE soli_tab.
  DATA: zls_et_soli TYPE soli.

  TRY.
      "Create send request
      gr_send_request = cl_bcs=>create_persistent( ).

      "Email FROM...
      gr_sender = cl_sapuser_bcs=>create( sy-uname ).
      "Add sender to send request
      CALL METHOD gr_send_request->set_sender
        EXPORTING
          i_sender = gr_sender.

      "Email TO...
      gv_email = 'guru@saptechnicalguru.com'.
      gr_recipient = cl_cam_address_bcs=>create_internet_address( gv_email ).
      "Add recipient to send request
      CALL METHOD gr_send_request->add_recipient
        EXPORTING
          i_recipient = gr_recipient
          i_express   = 'X'.

      CONCATENATE '<html><strong>Decission needed</strong><br/><br/>'
      '<tr><th style="color:blue;">Approval item</th>'
      '<a href=https://server:port/sap/bc/ui2/flp#WorkflowTask-displayInbox?allItems'
      '=true&/detail/XXX999_PGW/000000226597/TaskCollection(SAP__Origin=&#39;XXX999_PGW&#39;,InstanceID=&#39;000000226597&#39;)> click here to decide 000000226597</a>'

                   INTO zlv_longstring_message.

      CONCATENATE zlv_longstring_message '</html>' INTO zlv_longstring_message.

      CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
        EXPORTING
          text   = zlv_longstring_message
        IMPORTING
          buffer = xhtml_string
        EXCEPTIONS
          failed = 1
          OTHERS = 2.

      CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
        EXPORTING
          buffer     = xhtml_string
        TABLES
          binary_tab = t_hex.

      gr_document = cl_document_bcs=>create_document(
                      i_type    = gc_raw
                      i_hex    = t_hex
                      i_length  = '1200'
                      i_subject = gc_subject ).
      "Add document to send request
      CALL METHOD gr_send_request->set_document( gr_document ).

* set send immediately flag
      gr_send_request->set_send_immediately( 'X' ).
      "Send email
      CALL METHOD gr_send_request->send(
        EXPORTING
          i_with_error_screen = 'X'
        RECEIVING
          result              = gv_sent_to_all ).
      IF gv_sent_to_all = 'X'.
        WRITE 'Email sent!'.
      ENDIF.

      "Commit to send email
      COMMIT WORK.

      "Exception handling
    CATCH cx_bcs INTO gr_bcs_exception.
      WRITE:
        'Error!',
        'Error type:',
        gr_bcs_exception->error_type.
  ENDTRY.

The end result is as follows in the mail:

The hyperlink in the mail jumps to the URL, which in this case is the URL link to this specific workflow item in the FIORI inbox.

The coding explained

We use the CL_BCS class from SAP. BCS stands for Business Communication Service. This class provides all modern options to send mail. We set the sender and receiver.

We now build the mail in HTML. All is stored in zlv_longstring_message. We start with the <html> tag, and a header text in bold (strong). Then we add the text with the hyperlink (a href) in blue color.

The hyperlink towards the FIORi inbox contains ‘ characters. This does not convert well for all further on steps. So we replace ‘ instead the &#39 text. This &#39 text is the HTML character coding for an apostrophe (‘). In this way there is no misinterpretation at any browser.

At the end, we add the closing tag </html>. Now the HTML build up is ready and can be used to send.

The HTLM is converted via function modules SCMS_STRING_TO_XSTRING and SCMS_XSTRING_TO_BINARY to a binary. This binary is set as document with type HTM to the mail. The mail is then sent with immediate flag.

Check custom code for use of unreleased SAP objects

Custom code can use standard SAP code and SAP objects. Some of these objects might technically exist, but are in an unreleased status. This might mean SAP will not give support on them, or might remove them in a future upgrade.

Also when you want to move to the BTP ABAP cloud, you cannot use the unreleased code.

Questions that will be answered in this blog are:

  • How can I scan my custom code for use of unreleased standard SAP objects?

Tool preparation

First install the program SYCM_UPLOAD_RELEASED_OBJECTS by applying OSS note 2989803 – Check Usage of Released Objects with the Latest List of Released Objects.

And download the attached file in the same note in the attachments section;

Now run program SYCM_UPLOAD_RELEASED_OBJECTS and upload the file to a new SCI variant:

After the upload, you will find this new variant in SCI:

ATC run for unreleased code

Now you can start new ATC run with this newly created variant:

Run the variant for you custom code (can take few hours).

Result can be shown as special whitelist item:

ABAP code to write to application log

The SLG1 application log is a powerful mechanism to support team in SAP systems.

This blog will explain how you can write to the application log in your own custom ABAP code using ABAP code below.

It is recommended to create one single SE24 ABAP class for the application log that can be re-used in all your custom code.

Instantiation method

First method to create is the instantiation method:

   DATA: zls_log        TYPE bal_s_log,
         zlt_log_handle TYPE bal_t_logh,
         zlt_message    TYPE bal_t_msg. 

      zls_log-object     = ziv_object.
      zls_log-subobject  = ziv_subobj.
      zls_log-extnumber  = ziv_extnumber.
      zls_log-aluser     = sy-uname.
      zls_log-alprog     = sy-repid.


 CALL FUNCTION 'BAL_LOG_CREATE'
      EXPORTING
        i_s_log                 = zis_log
      IMPORTING
        e_log_handle            = zgv_log_handle
      EXCEPTIONS
        log_header_inconsistent = 1
        OTHERS                  = 2.

As input you have to give SLG1 object name and sub object name. You can re-use existing or create new custom one in transaction SLG0.

Now you have a log handler.

Add the messages

Now you can add a method to add one or more messages, re-using the log handler:

zls_msg      TYPE bal_s_msg,

      CALL FUNCTION 'BAL_LOG_MSG_ADD'
        EXPORTING
          i_log_handle     = zgv_log_handle
          i_s_msg          = zls_msg
        EXCEPTIONS
          log_not_found    = 1
          msg_inconsistent = 2
          log_is_full      = 3
          OTHERS           = 4.

Save the log

Create a method for saving the application log, again re-using the log handle:

    CALL FUNCTION 'BAL_DB_SAVE'
      EXPORTING
        i_t_log_handle   = zlt_log_handle
      EXCEPTIONS
        log_not_found    = 1
        save_not_allowed = 2
        numbering_error  = 3
        OTHERS           = 4.

Set up once and re-use

Set up the application logging helper class once in SE24 and tell all your developers to re-use it. You might find out that you developer already used the function modules above a lot in their Z code. This can be found with the ABAP code scanner tool. Check case by case when it makes sense to swap to the central helper class.

SE95 modification overview

Transaction SE95 can be used to get an overview of modifications in your SAP system.

Questions that will be answered in this blog are:

  • What is the definition of a modification?
  • How can I list all modifications in my system?
  • How can I make a download of all the modifications in my system?
  • How can I filter on real modifications and exclude the modifications caused by OSS notes?

Definition of modifications

This is the most tricky question: how many modifications are in your system? A question that will be asked to you every now and then. The answer can very between a very small number and a very large number. Even with the same system. This is because the way SAP is measuring modifications. OSS notes applied count as modifications. Classical user exits like MV45AFZF also count as modifications. Condition records (VOFM routines starting with RV) also count as modifications. But you can still consider the system as 100% standard.

Real modifications are only those where the customer willingly changed the SAP coding and its functionality, which is not based on an instructions from an OSS note.

In many cases with discussion on system quality, the number of modifications is misused! Be careful to check how your analysis figures will be used.

Modification browser

Start transaction SE95 to reach the modification browser initial screen:

You can now see the SE95 result list:

You can drill down based on the objects.

For a view per package, check the Packages display option on the first screen:

Listing for download

SE95 has a major setback: the list is very hard to export. The modifications are stored in database view SMODIDEVC (which is a view on SMODILOG and TADIR).

From here do select only the MOD (modifcations):

The resulting output list can be easily downloaded into an excel format.

SAP logon user exit hack

In SAP there is a user exit just behind the logon of a user. This can be used correctly, but also used for hacking.

Questions that will be answered in this blog are:

  • How to switch on the user exit after logon?
  • What is good use of the user exit after logon?
  • How to use the user exit for hacking?

Activation of the user exit

In transaction SMOD you can call up user exit SUSR0001:

This exit has only one component:

Double click on the exit to go to the Z code include:

To activate the exit, create a project in CMOD and and include this enhancement. Then double click on the include code ZXUSRU01 to activate the code.

Good use of the user exit

The user exit itself is described in OSS note 37724 – Customer exits in SAP logon. Example of good use it to restrict multiple logons in case you cannot switch on parameter login/disable_multi_gui_login. See OSS note 142724 – Prevention of multiple SAPGUI logons.

The exit is also used a lot by GRC and firefighter type of tools.

The user exit logon hack

In the user exit code, you can put in your own stuff.

As hacking example: copy function module PASSWORDCHECK and the screen that belongs to it to your own ZPASSWORDCHECK.

Modify the screen logic a bit. This is the original code:

Now change the code: the password is always reported back as ok. And the user input you catch in the field password is yours: you can mail it or store it somewhere for you to pick up later.

Put the altered code in the user-exit with logic:

IF SY-UNAME = 'target user name' and not capture before.    
  CALL Z function ZPASSWORDCHECK.    
  Store capturing.     
  Set capture flag.
ENDIF.

This looks as follows at runtime:

Many end users (and even auditors) will enter their password without thinking twice.

Alternatively you can use function module POPUP_GET_USER_PASSWORD as a basis for your copy: this has also clear text password:

The password field can be stored.

This has the following look and feel:

Detection and protection

It is wise to shield off this user exit from improper use and to yearly check the content of what is inside this user exit.

SAP interfacing: RFC

SAP has many different ways to interface. The RFC (Remote Function Call) protocol is one of the most wide used.

This blog will explain best practices around secure and correct setup of custom built ABAP RFC function modules.

Questions that will be answered are:

  • How to setup RFC enabled function module?
  • How to setup proper RFC error handling?
  • How to setup security in RFC enabled function module?
  • How strict is the S_RFC authorization handling?
  • Why is SAP_ALL not sufficient for RFC handling?

Creation of test RFC enabled function module

In SE37 you can setup an RFC enabled function module just like a normal function module. First create a function group. Activate that function group in SE80. Now you can create the function module. We will call our test module ZBAPIDEMO:

Important here in the first tab is to set the processing type to Remote-Enabled Module.

For testing we setup import and export tabs:

RFC export tab

Important here with RFC: set the Pass by value tickbox.

For tables use a suitable table type:

And setup the correct exceptions:

Here you can see 2 very important error messages that should always be implemented:

  1. An extra authorization check
  2. An error message when no data is found

Now we can implement the following simple source code:

   DATA: zls_coms_gen_textline TYPE coms_gen_textline.
 
   AUTHORITY-CHECK OBJECT 'S_CDMC'
   ID 'CDMC_AREA' FIELD 'A'
   ID 'CDMC_ROLE' FIELD 'U'.
   IF sy-subrc EQ 0.
 
     CASE zimport.
       WHEN 1.
         zexport = 'Hello world'.
       WHEN 2.
         zls_coms_gen_textline-entry = 'Hello world table 1'.
         APPEND zls_coms_gen_textline TO ztable.
         zls_coms_gen_textline-entry = 'Hello world table 2'.
         APPEND zls_coms_gen_textline TO ztable.
       WHEN OTHERS.
         RAISE not_found.
     ENDCASE.
 
   ELSE.
     RAISE not_authorized_business.
   ENDIF. 

What is important here in this source code:

  1. The authorization check is implemented and raises an error
  2. If no data is found the NOT_FOUND error is raised

With the SE37 test suite you can test diverse scenario’s now.

Calling RFC function module from another ABAP system

If you call this RFC function module form another ABAP sytem you have to make sure you have set and check the following exceptions:

  exceptions
      not_authorized_business = 1
      not_authorized          = 2
      system_failure          = 3
      communication_failure   = 4
      not_found               = 5
      OTHERS                  = 6.

There are 2 exceptions from the BAPI definition:

  1. NOT_FOUND (nothing found)
  2. NOT_AUTHORIZED_BUSINESS (our own implemented business authorization check)

4 exceptions should be implemented as part of the RFC framework:

  1. NOT_AUTHORIZED: this is the RFC authorization, which will be explained next chapter
  2. SYSTEM_FAILURE: the coding has caused a dump and the system returns and error message (see OSS note 2484377 – Error Message: “RFC Exception SYSTEM_FAILURE Raised; No More Memory Available to Extend an Internal Tab” Upon Executing a Data Extraction Run as an example)
  3. COMMUNICATION_FAILURE: the call to the other system fails. Most likely if you go to SM59 to the RFC destination and perform a connection test you will get a failure.
  4. OTHERS: something else went wrong

The developer should take proper care of these error situations.

Dear ABAP developers: the basis team member are also humans. They will make RFC configuration errors, they rely on the authorization team to assign the correct roles and they rely on infrastructure providers to make sure systems are up and running. Also the basis team will need to perform patching and upgrades to the system, which you as ABAP developer, are calling. So please don't blame the basis team for these exceptions, but please be a good developer and implement proper error handling. If you didn't implement proper error handling, and something went wrong on basis side, that caused your code to go wrong, think twice before putting blame on basis if your code is not handling the situation properly.

For reference: OSS note 1371131 – Correct error handling of RFC calls.

Security of RFC calls

Security of RFC calls is consisting of 2 layers:

  1. The RFC layer
  2. The business application code

You should always implement both layers!

The RFC layer is protected by authorization object S_RFC:

Here you can choose between a function group or even allowing per function module. Personally I would protect by function module. Background: create, change and display BAPI’s will normally be developed inside same function group.

There is a common misunderstanding that if you give SAP_ALL to a (background) user, this would solve the RFC authorization issues. This is not true. SAP_ALL does not contain the S_RFC rights. You have to hand them out separately.

Best practice 1: you might want to start with broad authorizations at the beginning of a development to rule out authorization issues. But you must definitely limit the rights before you make the development go productively live.

Best practice 2: as first statement inside each and every RFC function module, program a relevant business authorization check statement. This is an extra safety measure that is needed to protect important business data from authorization consultants that have handed out * authorizations in object S_RFC (* means all).

Best practice 3: check in transaction SM59 that the RFC callback protection is activated. Read this blog how a hacker can easily misuse if not properly setup.

Best practice 4: be careful on the RFC setup to avoid that hackers misuse the RFC jumping option. Read more in this blog.

More on checking the basis RFC security: read this blog.

Generic S_RFC check handling at basis level

The behavior of the S_RFC check is driven by the settings of RZ11 profile parameter auth/rfc_authorithy_check. Please make sure it has a setting of 6 or higher. Best is 9. A system with 5 or lower can be considered as insecure!

Background OSS note: 2216306 – S_RFC check and profile parameter auth/rfc_authority_check.

Setting up trusted RFC connections

Set up of trusted RFC connections are explained in this blog.

RFC performance

Check if you can use the RFC fast serialization option. This option is available for a lot of modern SAP systems. It is not activated by default. Read more on the fast serialization option in this blog.

Running SCI and ATC on standard SAP and add-ons

SCI and ATC are very powerful code scanning tools (see blog and blog). Unfortunately you cannot apply it to standard SAP and add-ons.

Analyzing standard SAP code is the responsibility of SAP, and they take good and secure code (since they provide good code, it is weird they don’t allow everybody to scan their code…). Unfortunately a lot of add-on providers do not.

The blog will explain how to scan code of standard SAP and mainly on add-ons.

Questions that will be answered are:

  • What is the background on not being able to scan standard SAP and add-on code?
  • Can I truly scan the code of a new OSS note 7 days?
  • How can I work around these restrictions and still scan the code of an add-on?

Background

The background of not being able to scan standard SAP code is explained in OSS note 1986391 – Using SLIN/SCI to check SAP standard objects. This note also explains you can scan OSS notes and transports for 7 days. After that time it is no longer possible. Unfortunately this rule also applies to add-ons.

Why run SCI on add-ons?

Why would you want to scan add-ons? Add-ons come with various quality levels. Ranging from very well written with much attention to performance and security. Some add-ons are full of performance issues and full of security leaks. Some are even allowing full dynamic read SELECT and UPDATE statement without any authorization check. This is heaven for a hacker!

The below method is meant for scanning these poor add-ons using the SCI tool for performance, robust coding and security.

ATC checks on non-SAP addons

First apply OSS note 2215288 – ABAP Test Cockpit: Analyzing Objects Using Arbitrary Prefix Namespaces.

For ATC checks, now run program SATC_AC_INIT_NAMESPACE_REG to add the namespace as registered for ATC.

See note 2439348 – SATC_AC_INIT_NAMESPACE_REG list is empty, if you get empty list.

See OSS notes: 2141202 – FAQ – ATC/CI: Analysing Objects with Custom Prefix Namespace ‘/MYSPACE/’ and 2313169 – ATC checks and ABAP Unit tests for objects in producer namespaces not possible

How to run SCI on SAP standard?

When you run the SCI tool on an add-on by selecting package or development object, you get the message that it does not contain any objects:

This is because your selection is first scanned for standard SAP and add-on objects. These are removed. So the result set is empty.

Goto transaction SE24 and select class CL_CI_OBJECTSET. Now select method BUILD_TADIRSET and display the code:

Put a break-point as statement if ENABLE_CI ne ‘X’.

Now start the SCI tool again. If the debugger stops at this statement, use debug and replace to change the content of ENABLE_CI to ‘X’. Now the skipping of SAP and add-on objects is not done. SCI will scan the code. It will still not use SLIN. But these are minor checks.

Bug fix OSS notes

Bug fix notes: