Tuesday, 29 November 2016

MVC (model view controller) framework for ABAP part 1

What program type?

This is a question I have often reflected on. When I create an OO based dialogue application, what kind of program should I use? Since the program has to manage at least one dynpro, we could choose between three types of program for our application:
  • A module pool
  • A function group
  • A report
Subroutine pools can not carry dynpros so we cannot use them. What type to use?

The module pool ist declared obsolete by SAP, so I decided to not use this one.

The objective of a function group is to host function modules, which are very uncomfortable to use in the OO environment (no automatic type determination of parameters, obsolete table types in parameters.

A report can contain dynpros and can be used even without the report events. In case of the need to create a real report with a selection screen, it’s naturally the only alternative (the framework supports also report-type programs). So I decided to create all my programs using reports. Another advantage is that I can always place a call screen statement unter start-of-selection, so my dialogue application can run directly from the editor pressing F8.

It’s not obligatory to use a report, though. )f you feel more comfortable using one of the other possibilities, the framework works as well. Once the program is created, you should define a main controller (I call it always LCL_CON_MAIN) as a subclass of ZCL_MVCFW_CON_MAIN and a model (LCL_MODEL). In some cases, the model could be also a public class, if you plan to reuse its functionality. Furthermore you will need one class for each additional controller. Create one controller for each subdynpro you use as well as each CFW screen control.

The model

The model component is a freely composed class that will keep the application data and do manipulations on it. All database accesses are done within the model. The model itself never interacts with the user, but only signals to the controller if something is do display or input is to be taken. One single model is typically, but complex applications can also have more of them.

The view

The framework uses the following types of views

Main dynpro: the main dynpro of the program (and there will be only exactly one; i’ll get back to this later) is the main view component. All further visible elements depend on it.

Sub dynpro: As we will see later on, the main dynpro is not intended to carry any fields. There is only a subdynpro area on it that spans the whole space. I normally create the main screen with the maximum size (200 li x 255 col). Any screen element such as input fields or custom controls will be created on a sub dynpro. You can have more than one sub dynpro and switch between them.

Selection screen: In a report-type application, there will be a selection screen, which we regard as a view component, too. I will introduce a selection-screen framework component in the next part.

CFW control view: Apart from the classical dynpros, any control type of the control framework will play the role of a separate view component

The controller

There will be one controller class for each view. The main controller manages the main dynpro and can react to user interaction via the GUI status functions, though this could be coded also in the sub dynpro controller. It also keeps a list of all instantiated controllers and will take care of the right instantiation, when a new one is needed. We will have a look at this in detail later on. It also should keep the main logic for the program flow.The CFW view controllers are responsible for the data flow to the dedicated screen control. Therefore, they keep a reference to the model in order to be able to get the data to display from there.

Framework architecture

The framework consists of the following repo objects:

  1. The main controller class ZCL_MVCFW_CON_MAIN. A program will define its own main controller inheriting from this class – all classes in the framework are abstract and need final classes in the program that inherit from these.
  2. The abstract dynpro controller ZCL_MCFW_CON_DYNPRO. It has a subclass for a subdynpro:
    1. ZCL_MVCFW_CON_SUBDYN: manage a subdynpro (it can also manage a dynpro in a popup). In the next part, I will introduce another subclass for selection screens
  3. The abstract CFW controller ZCL_MCFW_CON_CFW. It can be used to manage any CFW screen control
    1. ZCL_MVCFW_CON_ALV: a subclass of the above for the most common control ALV that contains a lot of useful stuff to manage an ALV grid control  (CL_GUI_ALV_GRID)
  4. An exception class ZCX_MCVFW_ERROR, which is quite generic and serves to pass exception situations to the controller

The coding is included in the demo application.

Demo application

The report ZP_MVCFW_ALV_DEMO (complete listing in the sources) is a simple application with a simple dynpro and two ALV grids in it. You can upload the demo application from the attached file ZP_MVCFW_ALV_DEMO.TXT.
Main screen

The main screen (see sources) contains one single element: a subscreen area (called SUBSCREEN) that spans over the whole available space. You can upload the screen from file ZP_MVCFW_ALV_DEMO_SCREEN_0001.TXT.

The flow logic:

process before output.
module pbo_0001.
call subscreen subscreen including sy-repid gv_subdyn.
*
process after input.
module pai_0001 at exit-command.
call subscreen subscreen.
module pai_0001.

Sub screen

The sub screen is the “working” screen. Here we have the input/output fields that we need. For the framework, it is indispensable that all fields are DDIC dependent and belong to the same structure.

You can upload the sub screen after having created it from the corresponding field

The sub screen in the demo application contains one field:

Screen logic:

process before output.
module pbo_sub.
*
process after input.
module pai_sub.

GUI interface of the demo application

To get the demo running, you will have to create a GUI status named MAIN. See the pictures to find the codes you have to create.
  • Set the code for the exit button to EXIT
  • Set the code for the back button to BACK
  • set the code for the cancel button to CANCEL
  • add the code SHOW to the application toolbar with icon ICON_DISPLAY
  • Furthermore, you will need a GUI title called MAIN with text “Display flight data”
The error class

To create the error class, just create the class as exception class with T100 interface and switch to the public section code. Then paste the coding from the demo application.

Methods of the framework

ZCL_MVCFW_CON_MAIN

This class is used as super class for the main controller (LCL_CON_MAIN in demo). It provides the following methods

Constructor

The constructor takes the program name as parameter. It is used in the SET PF-STATUS and SET TITLEBAR commands to specify the program. In the local subclass, call the super constructor giving the program name.

GET_INSTANCE

Factory-method (static). It will instantiate the class on first call,in other cases it returns the already created instance (singleton pattern).

GET_CON_DYNPRO

This is to be called from the PBO of subscreens to get the controller. Just like GET_INSTANCE, it will create the controller on the first call, afterwards it returns the already created controller. The framework keeps an internal table with all created controllers in memory

CREATE_CON_DYNPRO

When GET_CON_DYNPRO is called the first time, this method is invoked. Any program using the framework must redefine it with coding for the creation. See demo program for an example

GET_CON

This is the sibling of GET_CON_DYNPRO for CFW controllers. The type of the needed controller class has to be passed as parameter (for example: get_con( ‘LCL_CON_ALV_SFLIGHT’) ). In the demo application, constants are being used for the controller class names.

CREATE_ONE_CONTROLLER

Similar to CREATE_CON_DYNPRO. Redefine it and code the “create object” statements dependent from the input parameter that contains the class name.

GET_SELECTIONS

Used for report-type programs. Will be described in part two.

KILL_CON

Kill a controller (and the associated container)

PAI_EXIT

Can be used in case of exit commandos from the main screen.

PBO_MAIN

Returns the actually displayed sub dynpro and sets the PF-STATUS and TITLEBAR. To be called from the PBO module of the main screen

REFRESH

Calls the REFRESH method of each present container. Useful to do a complete refresh of all CFW controls

SET_SUBDYNPRO

Sets the sub dynpro number, the PF-STATUS and the TITLEBAR that are to be used during PBO. This method should be called during the first PBO in order to have a defined sub dynpro for the screen 0001. Normally you would call it from the constructor method of the main controller. Call it again, when a different screen is to be displayed.

ZCL_MVCFW_CON_DYNPRO

Constructor

Pass the DDIC structure name that contains the fields on the screen and the main controller to the constructor (in the constructor of your local derivation of the class).

INIT_SCREEN

Useful to clear all input fields

PAI

Is to be called from the module PAI_SUB. You can pass the screen structure to it, so it will compare all screen fields to the fields in the memory of the class. For each difference, PAI_FIELD_CHANGE will be called.

PAI_EXIT

Intended for exit commands on pushbuttons on the sub screen. No field validation will take place.

PAI_BEFORE_FIELD_CHANGE

Is called by PAI. Can be redefined for specific actions to be taken before the user input is validated.

PAI_FIELD_CHANGE

Is called by PAI. Each value of the given screen structure (parameter c_data of PAI) is compared to the correspondent structure in the memory of the class. For each difference found, this method is invoked where you can code reactions on changed field values on the screen.

PAI_USER_COMMAND

Is called by PAI after the field validation giving the user command. It has to be redefined and should contain reactions to user actions. You are free to decide if you want to handle user commands in a PAI method of the main controller or in here.

SHOW_ERROR

Called by PAI and PAI_FIELD_CHANGE in case of occurrence of an exception. Can be redefined in order to react accordingly.

ZCL_MVCFW_CON_CFW

Constructor

The constructor takes the GUI container where the CFW control should be placed as parameter. Normally a container will be created in CREATE_ONE_CONTROLLER before creating the object.

CHECK_CHANGED_DATA

Many CFW controls have input capabilities (Text editors, ALV grids…). Redefine this method for the CFW control to get the input into the program. In ZCL_MVCFW_CON_ALV for instance, it is redefined containing a CHECK_CHANGED_DATA call to the ALV object.

FREE

Is used by KILL_CON of the main controller.

GET_CONTAINER

Getter for the container of the control.

HIDE

Sets the container to invisible (useful for docking containers)

REFRESH

Generic refresh method. Each concrete CFW control can implement its own version. See ALV control for an example.

UNHIDE

Reveals the container after a HIDE( ) call.

No comments:

Post a Comment