SAP’s traditional applications are developed using stateful technologies. These stateful transactional applications rely on a server session along with application buffers that can fulfil client requests (user interactions with multiple backend round trips) until the user has saved the data changes and finished his/her work. In stateful applications, data entry and data updates work on a temporary in-memory version of a business entity which is only persisted once it is sufficiently complete and consistent. The life time of this temporary version is tied to the UI session.
However modern cloud-ready apps require a stateless communication pattern, for example to leverage cloud capabilities like elasticity and scalability. There is no fixed backend session resource along a business transaction for each user and the incoming requests can be dispatched to different backend resources. On the other hand apps are stateful from an end-user perspective. Business data that is entered by the end user needs to be locked, validated and enriched via business logic on the backend side.
The draft concept fills this gap between a stateless communication pattern and a stateful application. Draft-enabled applications allow the end user to store changed data in the backend and continue at a later point in time or from a different device, even if the application terminates unexpectedly. This kind of scenario needs to support a stateless communication and requires a replacement for the temporary in-memory version of the business entity that is created or edited. This temporary version is kept on a separate database and is known as draft data. Drafts are isolated in their own persistence and do not influence existing business logic until activated.
In this blog we will take a look how the draft concept is implemented in the ABAP RESTful programming model. But before we dive into this a small introduction of the framework might be in order.
The ABAP RESTful programming model
The ABAP RESTful Application Programming Model (in short RAP) defines the architecture for efficient end-to-end development of intrinsically SAP HANA-optimized OData services (such as Fiori apps) in the SAP Cloud Platform ABAP Environment or in the Application Server ABAP. It supports the development of all types of Fiori applications as well as publishing Web APIs. It is based on known technologies and frameworks such as Core Data Services (CDS) for defining semantically rich data models and a service model infrastructure for creating OData services with bindings to an OData protocol and ABAP-based application services for custom logic and SAPUI5-based user interfaces.
Drafts in the ABAP RESTful Application Programming Model
Draft is an option that you can use for application development with both, the managed and unmanaged implementation scenario. In all scenarios the draft is handled by the RAP runtime framework. You, as an application developer, do not need to care about how draft data is written to the draft database table. This is done for you. Of course, adding draft capabilities to your business object might imply changes in your business logic also for the processing of active data that you are responsible for. In addition, RAP also offers implementation exits for cases in which you need business service-specific draft capabilities that impact the draft handling.
In the steps shown below can be seen how draft can be implemented in an SAP Fiori elements app which makes use of the ABAP RESTful programming model.
The travel app
As starting point we use a simple SAP Fiori elements app based on the well-known flight data model. Within this app a user can create, update and delete the travel business object and maintain its respective bookings. The app makes use of the so called managed scenario. In a managed scenario, many of the behavioral elements are implemented by the RAP framework itself. All required standard operations (create, update, delete) must only be specified in the behavior definition to obtain a ready to-run business object. The technical implementation aspects are taken over by the business object runtime infrastructure. Additionally the app contains a number of business object specific actions, determinations and validations which have been implemented separately outside of the managed scenario.
Enabling the draft handling
Enabling the draft handling in the ABAP RESTful programming model involves adjustments to several components of the ABAP RESTful programming model. Changes have to be done in the BO behavior definition, the behavior projection and in the behavior implementing class(es) . These are highlighted in the RAP development flow below.
Every step will be described below in more detail below.
Enable the draft handling in the BO behavior definition
Activate draft handling in the base business object
In the first step we have to tell the behavior definition of our Travel base business object that we want to use draft handling. This can be done by adding the statement with draft just as can be seen below.
Draft database table
As the draft is now managed by the framework, we need to specify a draft database table for each entity in the business object model. A draft table can be defined by the statement draft table and a table name to your liking. In our case we use ZRAP_DTRAV_SN01 as the draft table.
By selecting the option ‘Create draft table’ from the quick fix menu the draft table will be generated instantly based on the defined model and shown in the appropriate editor.
Draft enabled associations
As this is now a draft enabled business object we also have implicitly draft enable the compositions and associations in our business object model. This can be done by adding again the statement with draft to the all the relevant compositions and associations.
Draft business objects require a total ETag. This designated field on the database table is updated by the RAP runtime framework as soon as an active instance is changed. The total ETag always refers to the complete BO. As soon as an instance of any BO entity is changed, the total ETag is updated. Its value is compared when resuming a draft instance to ensure that the active data has not been changed after the exclusive lock has expired.
The total ETag field is defined on the lock master entity (currently identical to root entity) and optimistically controls the whole business object regarding concurrency on the active data.
Preparing Draft instance for activation
The last change we have to make in the BO behavior definition is to define which validations will be triggered during the activation of the draft instance.
Before draft instances become active the Fiori elements UI calls the draft determine action prepare. This call takes place in a separate OData change set to allow it to save the state messages even if the activation fails due to failing validations. In order to execute our validations during prepare, we need to assign them to the draft determine action prepare. The validations validateAgency, validateCustomer and validateDates have been added.
Enable the draft handling in the behavior definition projection
Besides enabling the draft handling in the behavior definition of the travel app you also have to expose the functionality in the business object projection layer.
For our travel app this means executing the following three changes:
- Enable the draft handling in the projection, by adding the statement use draft; in the header section. Otherwise the projection would behave like if no draft has been enabled for the business object.
- Enable the draft handling for the associations exposed in the projection.
- Disable etag handling. Because SAP Fiori elements-based UIs do not currently support the Etag handling together with the draft handling for OData V2, you have to disable it in the projected behavior definition.
Change business object behavior implementation
The introduction of draft handling has added two predefined actions to the business object. The draft determine action Prepare and the draft action Edit. They have to be added to the authorization control to make sure that these actions are handled correctly by the authorization check. This can be done by modifying the GET_INSTANCE_AUTHORIZATIONS method of the object behavior implementation class.
When we set a break-point in method GET_INSTANCE_AUTHORIZATIONS method and activate a draft we can see in the debugger that an authorization requested is executed for the draft action PREPARE.
A Draft enabled application
With all the coding in place the travel app is now officially draft enabled. But what does this exactly mean. The best way to show this is start up our app and explore the new features.
The first thing we notice is a new filter field that allows for filtering on the editing status.
With this new filter we can select BO entities based on their editing status. For example filtering on Own Draft gives you all entities which have been modified by you but which not been saved yet.
A second thing that has changed is visible when a new entity is being created or an existing entity is modified. In this case we see, every time a field is changed, the text Saving draft … appear followed by the message Draft Saved. In this step the draft table is updated with the latest state of the BO entity.
This can be verified by checking the respective entries in the draft database table.
Another feature that the draft enabled app supports is that you can store travel entities even if they have errors or are missing mandatory fields. As the error messages are state messages they are stored on the database and belong to the state of the business object instance. So even when you leave the screen and revisit your draft entity you will see the messages directly when opening the object page without revalidating the instance on the back end.
The last thing worth mentioning is that when the browser window is closed the data loss message is no longer shown because all changes are persisted in the draft table and are recoverable in the next session.