8.2.6 – Restricting meaningful BO-interaction using properties
In the book “ABAP to the future”, this chapter is named slightly different: “Disabling certain commands using validations”. This original title mixes two actually different aspects which should – in my opinion – clearly be separated: Action validations and action properties. As this is a common misunderstanding, I will dedicate this chapter to properties and handle validations in the next one.
As written in the book, it is of interest for a consumer, whether an interaction with some business entity is possible (e. g. whether a button can be pushed or not). Similarly, there is good reason that some attribute should not be visible or displayed only read-only: The interaction, that this attribute can be changed shall not be allowed. This is “disabling in advance to the actual interaction” is particularly relevant for a human consumer. Usually, the business logic which is being executed when deciding about whether a button shall be enabled or not is a subset of the checks which are being executed before the action would be performed. For example, we could enable the button which makes a monster howl at the moon only for monsters with heads. In addition, when trying to howl at the moon, it shall be verified that if the monster is a werewolf, the current time is a full moon. If the user asks a werewolf to howl at other times, an error message shall be created (but no howl). As this werewolf-specific check (“validation” in the BOPF terminology) is quite special, it is better with respect to user experience to explain the impossibility to the user using a message instead of just disabling the button: The user who is not handling werewolves daily would not be able to understand why the button is not enabled. Thus, in BOPF, there are different mechanisms for both aspects: While validations actually verify the requested interaction with or the state of an instance, properties are an additional mechanism to implement business logic which helps to avoid impossible interactions by a human consumer. Consequently, there is an own core-service “retrieve properties” which allows to execute this business logic.
The core-service “retrieve properties” is an optional channel for a user interface in order to request information about limitations of interactions with a BO instance (precisely with the instance of a BO node).
Multiple aspects of the model can be subject to properties (there are some few more than listed below, but they are most likely not relevant for your business and would be really tricky to explain):
- Actions: Whether the action is enabled (usual visualization: Button is active or grayed out)
- Node attributes:
Enabled (usual visualization: Field is hidden from the UI if not enabled)
- Read-only (usual visualization: Field is changes from input-field to text-label)
- Mandatory (usual visualization: Field is highlighted, e. g. with an asterisk)
- Nodes: Delete enabled (usual visualization: The delete-button is hidden if not delete enabled)
- Association: Create enabled (usual visualization: The new-button in order to create a sub-node in a tabular control is de-activated if not create enabled)
Properties can either be statically modeled (e. g. the hat-size-code shall always be read-only, as it’s being determined from the hat-size) or they can be dynamically determined through a property-determination. We’ll do the latter now for our action to howl at the moon.
Implementation of a property-determination
A property-determination is a particular configuration of a determination (we’ve been covering that in the previous chapter). As all kinds of determinations, the implementation is an ABAP-class implementing the determination interface /BOBF/IF_FRW_DETERMINATION.
The interface methods CHECK and CHECK_DELTA are or no relevance in this case, as there’s no “change” when retrieving properties, so let’s directly head to the EXECUTE-method.
METHOD /BOBF/IF_FRW_DETERMINATION~EXECUTE.
* Technically, properties are captured at runtime in a technical subnode (which we don’t have to model explicitly). A helper class facilitates the handling of this subnode (sadly to be constructed directly)
DATA lo_set_property TYPE REF TO /bobf/cl_lib_h_set_property.
CREATE OBJECT lo_set_property
EXPORTING
is_context = is_ctx “ Determination context
io_modify = io_modify. “ Reference to modify object
DATA lt_root TYPE ZMONSTER_T_ROOT. “The combined table type of the node to be retrieved
io_read->retrieve(
exporting
iv_node = zif_monster_c=>sc_node-root
it_key = it_key
it_requested_attributes = VALUE #( (zif_monster_c=>sc_node_attribute-root-number_of_heads ) )
importing
it_data = lt_root ).
LOOP AT lt_root ASSIGNING FIELD-SYMBOL( <ls_root> ).
IF <ls_root>-number_of_heads = 0.
* Disable the action to howl at the moon if no head’s available
lo_set_property->set_action_enabled(
EXPORTING
iv_key = <ls_root>-key
iv_action_key = zif_monster_c=>sc_action-root-howl_at_the_moon
iv_value = abap_false ).
* Also, the total number of eyes which we calculate as total eyes of all heads is not relevant in this case, let’s disable this attribute (so that a UI knows it can hide it)
lo_set_property->set_node_attribute_enabled(
EXPORTING
iv_key = <ls_root>-key
iv_node = zif_monster_c=>sc_node-root
iv_node_attribute = zif_monster_c=>sc_node_attribute-root-total_eyes
iv_value = abap_false ).
ENDIF.
ENDLOOP.
ENDMETHOD.
I hope you now got an idea of what properties are and why they should be used in order to determine the potentially meaningful interactions with a node instance. If you’re still in doubt, please do ask!
In the next chapter, we’ll have a look at validations which includes options how to really prevent an interaction.