Skip to Content

In this blog post, I want to share some ideas about the processing of a single dialog step in an application. I am using the dialog step of a stateless Business Server Page application as example, but the basic ideas essentially hold for any user interface.

Pre-Requisite: Model – View – Controller (MVC)

Model-View-Controller (MVC) is a basic architectural pattern that is applicable for any software which involves interaction with a human user (i.e. not for software embedded in an engine or automat). It is about factoring out the code parts that are responsible for the UI from the “models” – which is all the rest, independent from that particular UI. The UI code parts themselves are divided into views – the actual UI elements presented to the user – and controllers – which co-ordinate the activities of views and models.

First Phase: Initialization

In this first phase, the controller gathers the necessary ressources for the dialog step: If there are models needed for the current state of the application, the instances are built or accessed. The controller analyzes the incoming form fields by their name and puts them into an own data structure. If there was state from the previous dialog step, it will be restored in this phase if necessary.  

In a stateless BSP application, not the complete session with all its data will persist a dialog step – instead, only the necessary parts of information survive, following the on-demand paradigm. This small amount of data which is really necessary for the execution of the next dialog step, is known to the developer who designs the application. He stores these data in the database table SSCOOKIE which is designed for storing session-specific general data clusters (it uses the EXPORT TO DATABASE idiom for storage). In the presence of a web dispatcher with varying application servers for each dialog step, it makes no sense to put theses session data to the memory only. Hidden form fields in the web page itself would be an alternative – but they are commonly considered too tedious; they are useful, however, for very small web applications or very tiny bits of information to be kept.

In such a (technically) stateless web application, it is a task of this first step to revive the session data from the data base. From the second step onwards, the developer can then work with the comfortable illusion of continuous state.

Second Phase: Receiving View Data

When the first step is completed, all the models and auxiliary objects are available for use. Now the data coming in from the user interface have to be put into the correct places in their server’s counterpart.

An input field on the screen has a corresponding domain on the server, usually somewhere in some model’s data. In this step,

  • the controller dispatches the user’s input – which comes in as a sequence of the characters he typed, i.e. as a string, to the model that is responsible for it;
  • the model checks whether the input is valid – and triggers an error event if this not the case, stopping the data transfer for this field and collecting a specific error message describing the problem;
  • if the input string is valid, the model converts it into the internat data format. For example, the string “4/17/2013” representing a date, will be converted into the internal type D format as we see it in the debugger: an eight place data object with the value “20130417”;
  • finally, the result of this “to internal” conversion is stored in the corresponding data object.

To indicate the correspondence, we use the mechanism of data binding: The name of the input field encodes in a readable manner to which data object of which model the value refers. See the SAP Help for the basics of such a syntax.

An application may work with many models at once. So the total set of incoming fields can be divided into several groups, and each of these groups (name/value pairs coming from the screen input) will be addressed to a particular model.

In this step, we have to consider field dependencies: Often it doesn’t make sense to validate a field B if the validation of another field A had failed. These dependencies and priorities can be mapped into execution logic in this step. By the way: This logic could in large parts be programmed in a general and declarative manner. Only specific field validations have to be programmed explicitly. A framework can do the main part here.

An application may work with many models at once. So the total set of incoming fields can be divided into several groups, and each of these groups (name/value pairs coming from the screen input) will be addressed to a particular model.

Third Phase: Handling the User Command

I am using the singular “the user command” on purpose here: A dialog step is always triggered by exactly one user action. Therefore, it is completely sufficient to encode this action in one and only one field, which in GUI applications traditionally has the name FCODE.

The prototypical example here is: The user hits a button. Then the content of the FCODE will say which button it was. This way, the user can trigger an action which will be performed in this third step. Following the Command Design Pattern, a command object could be instantiated which implements an interface consisting of the execute() method. I used a more simple approach: Dynamic method invocation. From the FCODE, say “SAVE”, I form the method name “FCODE_SAVE” and try to call this as a controller method (indeed, all user command handlers belong to the controller in the MVC model). If no such method exists, nothing will be executed (the CX_SY_DYN_CALL_ILLEGAL_METHOD exception is caught with an empty CATCH clause).

Even this case – that nothing happens – makes sense: In some cases, it is required that hitting the “Enter button” will cause a server roundtrip – propagating all the user data into the corresponding fields and reacting on data changes, but with no particular action. For this, an explicit FCODE can be designed, say “ACTU”, with an empty handler method FCODE_ACTU.  

How is the dependency from the previous step: “Receiving View Data”? Usually, it is not desired that an FCODE will be executed if there was an error in the user input validation: The user should correct his input errors before he can save the document (say). 

I solved this dependency by employing a non-persistent overall message collector (using the application log functionality – development class SZAL): If an error has been collected during the field validation, the phase “handle user command” will be skipped:

* Field validation
            get_viewdata( ).
* Handle User Command - but only if there were no errors:
            if check_valid_data eq abap_false or
                 log->get_highest_type( ) na 'EAX'.
                  handle_fcode( ).
           endif.

In some cases, it is wished to surpress this dependency: Think of the screen data divided into several tabs – you wouldn’t wish to surpress the event “change tab” only because a field in the current tab is not yet filled out. It is for these special cases that the controller flag check_valid_data can be switched off to force user command handling.

Fourth Phase: Do the Subsequent View(s)

After having finished the phase “do user command”, everything is known which needs to be known for sending the followup view(s). Like the FCODE in the third phase, I used a special field PANEL for the fourth phase. The name PANEL is actually stolen from SAP’s old and venerable screen sequence control (function group V00F), where the term means something quite similar.

Like the FCODE, the PANEL is a string, encoding a certain view state of the application. The necessary views that have to be instantiated and processed in a certain PANEL, are declared, not programmed, in an XML document accompanying the BSP application (which I called “Flow Logic” – a file stored as config.xml in the MIME branch of the BSP application).

Here is a primitive example application, which may give you an idea: http://bsp.mits.ch/buch/zz_hallo_welt/hallo2.do

For example, a simple application often has three panels: “entry”, “list” and “detail”. There will be an invariant part of each of the corresponding pages in the browser (containing the <html>, <head>, <body> tag and some constant parts like the navigation area and other sidebars). And there will be variable parts which have to be selected depending on the actual PANEL. These correspond technically to HTML fragments, encoded in BSP views, and plugged into the corresponding parts of a main view.

An important rule is: At the beginning of Phase IV, the field PANEL has to be known. It should never be changed afterwards (as changes will be of no effect). For example, an event handler in an entry screen, requiring the selection of certain documents depending on the entered selection criteria, will be coded like this:

method handle_select.
  get_model( 'order_selector' )->select( ).
  set_panel( 'list' ).
endmethod.

In line 2, the model method for order selection is called. It knows the selection criteria: They had been bound already in Phase II to “order_selector” model attributes. Its result will be a list, say a public model attribute “gt_result”, to be referred to in the list view.

In line 3, the panel is switched from “entry” to “list”. Thus, the controller knows which views have to be processed in this current Phase IV.

One of the views participating in the “list” panel, may call a list view control, referring to the result list via databinding. So in the HTML code of the view, we may find the following call:

  <z:table binding="//order_selector/gt_result"/>

Here, <z:table> is a custom BSP element, containing in its implementation details the HTML code to be produced for representiong the ABAP table gt_result. I have some “default” components for doing this work, but in many projects there are some more sophisticated requirements on table views, which I handle with project specific BSP elements, delegating whatever they can to my basic <z;table> element.

It is in this phase that the so-called field selection has to be performed, i.e. the determination of input control properties like “readonly” or “invisible”. For an input field like

<z:input binding="//order/gs_head.sold_to"/>

there has to be a callback to the controller – and, from there, also to the model – in order to determine whether the order’s sold-to party may be changed in the current state of the order.

Observe that in GUI applications, the transition from Step III to Step IV corresponds to the transition from Process After Input (PAI) to Process Before Output (PBO)

Fifth Phase: Finish

There is an event which all involved controllers and models should receive, signaling that the response is now complete and ready to be sent to the user. The content of the response can’t be changed anymore in this step.

This phase is necessary only for (technically) stateless applications: They have the chance to write back the current session cookies to the database, so that they can be restored in the next dialog step.

Summary

My feeling is that this five phases model of a dialog step is somehow universal. For stateful applications, it reduces to a three-phase model (ignoring the very first and very last dialog step of the user’s session). It is a synchronized model, meaning that all the involved controllers participate in it: If we are in a certain phase, then all controllers with no exception have finished the precedent phases. For controlling phase III (user command) and phase IV (do views), a single string  encoding the necessary information suffices: FCODE for the user command, and PANEL for producing the output.

Reference

Rüdiger Plantiko: Das BSP Praxisbuch. dpunkt Verlag 2007 (German language).

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply