Friday, 5 March 2021

Be Prepared for the Upgrade 2105! Clean Up your RAP Business Objects to Adapt them to the Upcoming Changes

With release 2105 of SAP BTP ABAP Environment, SAP releases more business object (BO) contract checks for the ABAP RESTful Application Programming Model (RAP) to help you make your RAP implementation consistent, user-friendly, and compatible with further RAP features. These contract checks ensure that both, the consumer and the provider can rely on the consistency and the correctness of any transactional request. Requests that are not contract-conform may result in short dumps, triggered by these checks.

In the following, you will find explanation and solutions to prepare your code for the upcoming checks, even before the upgrade takes place and thus help you to prevent problems after the upgrade.

Using Data Type CURR

The decimal shift logic for currency amounts of data type CURR only works in a consistent way across different channels and consumption frameworks if the data type for currency amounts is of type CURR with two decimals. That’s why, RAP only allows you to use the data type CURR if it is defined with two decimals.

If you use this data type with another number of decimals, you will get an error on creating a new service binding. If you already have an OData service that uses data type CURR with more or less than two decimals, you will now get a metadata error, and you will see an error message in your service binding.

Excursion:

The decimals that are specified in the data type define the numbers of decimals with which the amount is stored on a DDIC database table:

Example:

Amount CURR(23,1)   CURR(23,2)   CURR(23,5) 
123,45 1234,5   123,45  0,12345

The number of decimals with which the currency amount is displayed on a Fiori UI and other outputs depends on the currency that is referenced by the amount field. The referenced currency code field must have ABAP type CUKY  (which is a CHAR(5) field with allowed values in table TCURR). Their decimal places are defined in database table TCURX.

Example:

1.234,56 EUR (2 decimal places)

123.456 JPY   (0 decimal places)

123,456 KWD (3 decimal places)

Since storing and output formats are not necessarily the same, an elaborate shifting logic is applied throughout the different channels of a RAP service. Consistency can therefore only be ensured if the amount uses data type CURR(x,2).

How to solve the problem:

Check if you can avoid using fields with data type CURR that have more or less than two decimals in the data model for your RAP service.

If there is no other way in your RAP Service than using the data type with a number of decimals unlike two, adjust the number of decimals in the CDS view that uses those data elements by casting the element to data type CURR(x,2).

◉ Cast an element Amount_m with data type CURR(x,m)  (where m > 2) to CURR(x,2) with the following casting logic:

      cast(
            cast(
                  Amount_m as abap.dec(x,m)
                ) * 1000   as abap.curr(x,2)
          )  as CastAmount_m,

The data type has to be cast to type abap.dec(x,m) (packed number) first, before it can be cast back to a currency amount type to avoid warnings for casting to an identical type.

Once cast to abap.dec, multiply the amount with a multiple of 10 (depending on the number of decimals of the original type) to get the amount with two decimals without losing digits.

◉ Cast an element Amount_1 with data type CURR(x,1) to CURR(x,2) with the following casting logic:
      cast(
            cast(
                   cast(
                         Amount_1 as abap.dec(x,1)
                       )    / 10  as abap.dec(x,2)
                ) as abap.curr(x,2)
           ) as CastPrice1,

The division by 10 triggers the conversion to type abap.decfloat(34). Since abap.decfloat(34) cannot be cast to abap.curr, it has to be cast back to abap.dec before it can be cast to abap.curr(x,2).

ABAP RESTful Programming Model, ABAP Development, SAP ABAP Exam Prep

The casting logic for fields with data type abap.curr(x,0) is done analogously.

◉ On writing access, the incoming values must be converted to the original data type. This can be done by using operation augmentation in the projection business object if the casting logic for read access in the CDS projection view. By using augmentation, the incoming values is converted before the request reaches the transactional buffer and any potential further checks during runtime are executed on the values that are already converted to the format on the database table.

If the casting logic is done in the projected CDS view, the backconversion for incoming values must be done in a determination for managed business objects or in the modify implementation method for unmanaged business objects.

Implementing Read-Only Operations and Characteristics


It is not allowed to use MODIFY statements in the implementation of the following behavior definition operations and characteristics:

◉ read
◉ read-by-association
◉ function
◉ feature control
◉ authorization control
◉ validation
◉ lock
◉ precheck

The listed behavior is uniquely read-only, which means it does not change data on the database and therefore any modify operation is forbidden in their implementation.

If you use a MODIFY statement in read-only implementations, you will get an error during runtime when the implementation is called.

How to solve the problem:

Remove any MODIFY statement in a read-only implementation.

Check if the behavior is really modeled in the correct behavior definition operation or characteristic.

◉ If you want to use MODIFY in a function implementation, implement the logic in an action instead. A function is only designed for read-only access to the database.

◉ If you want to use MODIFYin a validation implementation, implement the logic in a determination instead. A determination is designed to change data based on incoming values. A validation just checks if the incoming values are correct.

◉ If you want to use MODIFYin any other read-only implementation, implement the logic in a behavior pool implementation that allows changes on the database.

Consuming Instance Authorization and Feature Control in Managed BOs


With 2105, instance authorization and feature control is called once for all requested operations, and not for each operation separately. In other words, there is no separate authorization or feature control check for operations using %CID_REF.

If instance authorization or feature control depends on the successful execution of a preceding operation in the same request, the authorization or feature control might be denied because the instance checks are checked only once for all operations before any operation is executed.

Example:

A consumer issues an update and an action request in one EML call and the authorization for the action depends on a value the update request modifies. Since authorization is only checked once for both operations, the action might be involuntarily denied, even if the update would set that value for which the consumer would be authorized.

How to solve the problem as BO provider:

Check if the change during runtime has an impact on the authorization and feature control results for interdependent operations. If needed invoke a proper authorization or feature control check within the action implementation.

How to solve the problem as BO consumer:

If you want to ensure that the authorization and feature control is checked for each operation separately to avoid interdependencies between operations, issue a separate request for each operation.

Issuing Modify Requests for Read-Only Fields in Managed BOs


Stricter checks are introduced for dynamic feature control. The managed runtime framework used to ignore fields that were dynamically set to read-only by dynamic feature control in update requests. The read-only fields were not updated and the incoming values were ignored, but the others were processed and saved to the database. The consumer did not get any information that the values for the read-only fields were not processed.

Now, the managed runtime framework rejects such requests that attempt to update fields that were dynamically set to read-only and the consumer receives direct feedback about the rejected request.

How to solve the problem:

The consumer can request the permissions to check which fields are modifiable before executing update requests.

Example:

    GET PERMISSIONS ENTITY Entity
      FROM  InstanceKey
      REQUEST RequestField
    RESULT DATA(result_permission)
    FAILED DATA(failed_permission)
    REPORTED DATA(reported_permission).

Implementing Instance Feature and Authorization Control in Unmanaged BOs


Before the upgrade to 2105 the unmanaged runtime framework did not call the instance feature or authorization implementation before modifying operations. In UI scenarios, these implementations were just called for the consumer hints. The authorization check had to be implemented inside the modify implementation. This changes with 2105 with possible impact for the BO provider.

How to solve the problem:

◉ If possible, move the authorization and feature control logic to the corresponding implementation methods. Make sure that the related messages are moved as well, so that messages are returned to the consumer if the request is denied due to authorization or feature control issues. If not, only a generic message will reach the consumer.

If moving is not possible, you can leave the implementation method as is and opt out via the following code:

    cl_abap_behv_aux=>get_current_context( IMPORTING for_permissions = DATA(for_permissions) ).
    IF for_permissions = abap_false.
      RETURN.
    ENDIF.

◉ If authorization or feature control is denied in the corresponding implementation methods, the implementation for the corresponding modify request is not called at all. Check your modify implementations for any side effects that might not be called if the execution of the modify request is denied by authorization or feature control.

If you stick to these guidelines, the upgrade to ABAP environment 2105 will pass smoothly and your RAP implementation will be more consistent and stable afterwards. The action to solve the problems can be taken immediately, so you can eliminate the problems even before they arise.

No comments:

Post a Comment