You are on page 1of 27

WIRING HETEROGENEOUS FEEDER MODELS

TOGETHER OR THE FAIRYTALE OF HNSEL


AND GRETEL
Introduction
Recently I was asked as a reply to one of my previous blog posts, wether it is possible to
wire multiple UI building blocks to one target. The target could be a transaction
component in order to save all of these models when the users presses the Save
button in the UI.
The exact question was:
If we have a GAF with several steps and at the last step we want to save all the
GUIBBs. Some GUIBBs have there own model.We have created a WD component with
interface IF_FPM_TRANSACTION. We want to transfer all the GUIBB models to the
transaction component.Wiring would be nice, but we have more sources to the
transaction component. That is the reason why I would like to have more sources to a
target. What would you do? We can always use a factory singleton, but if we do that
then the wiring would not be needed anymore.
Unfortunately, SAP says clearly, that every UIBB may serve as a source for wiring
multiple times, while it may serve as a target only once.
To answer the question, having a FPM transaction component as a target for multiple
UIBBs is not possible. But there is a workaround, which could help solving this issue.

The fairytale of Hnsel and Gretel


The basic question is, how heterogeneous feeder models can be connected to a single
UIBB feeder model which eventually performs a Save-operation on all the received
feeder models.
This is where a commonly known fairytale comes into the scene.
Imagine, we had a Guided Activity FPM application. The first steps shows the Hnsel
UI-Building Block which has its own feeder model to read the data and save it
afterwards. The second step is the Gretel UI Building Block which has a totally
different feeder model with its own data. The main question is: What happens to these
feeder models and what are the further operations invoked?
Everyone who knows the fairytale already has the answer: Both are held captive by a
witch. But what does that have to do with our FPM application?
Technically spoken, we need to transfer both feeder models to a composite feeder
model. This is, where the composite pattern is used.
Both feeder models need to implement the same interface
ZIF_FPM_SAVEABLE_FEEDER_MODEL which forces its implementers to implement a
SAVE( )-Method.
ZIF_FPM_COMPOSITE_MODEL inherits from ZIF_FPM_SAVEABLE_FEEDER_MODEL and
describes what a composite feeder model should be able to do. Despite the SAVE( )method, it requires another method +ADD_MODEL(IO_MODEL :

ZIF_FPM_SAVEABLE_FEEDER_MODEL). The composite feeder model is implemented by


ZCL_WITCH_MODEL.
This means, the witch model may include other feeder models and subjects them to a
common treatment, which is, in this very example, the Save-operation.

The wiring behaviour of the UIBBs now needs to work like this:
1. If the input which comes from a wire, is not initial, the UIBB checks if the input is a
composite feeder model of type ZIF_FPM_COMPOSITE_MODEL (to do so, simply downcast the connectors output to an instance of type ZIF_FPM_COMPOSITE_MODEL and
catch the CX_SY_MOVE_CAST_ERROR exception, if raised)
2. If no input was provided, or the input had the wrong data type, a new composite
model of type ZIF_FPM_COMPOSITE_MODEL is created by the UIBB
3. A new outport of the UIBB is created which outputs a composite model of type
ZIF_FPM_COMPOSITE_MODEL
4. The UIBBs feeder model is added to the output using the ADD_MODEL-Method of the
composite model
This approach allows you to wire multiple UIBBs, who have a completely different feeder
model, together. The output of every feeder model will be an instance of type
ZIF_FPM_COMPOSITE_MODEL. Now weve got several wiring possibilities to wire the
UIBBs and the FPM transaction component together.

Option 1 The FPM transaction component


pushes ZIF_FPM_COMPOSITE_MODEL to the
feeders
Both feeders receive the witch, which is an instance of type
ZIF_FPM_COMPOSITE_MODEL. Every UIBB adds its own model by calling the

ADD_MODEL method. In the end, the witch holds captive all the feeder models.

Option 2 The FPM transaction component


receives ZIF_FPM_COMPOSITE_MODEL
The UIBBs are connected in series. The last chain link is the transaction component. In
contrast to the fairytale, the witch is created by Hnsel and is handed over to Gretel.
The transaction component receives the witch in the end. Again, the witch holds captive
the two other feeder models.

Conclusion
If feeder models need to be transferred using wires, a common interface and the use of
the composite pattern may be an option, if the implementations of the feeder models
differ. This is often the case, if the UIBBs in the application were initially build up for
another use case, but now need to be combined for a new application.
However, the interface which needs to be implemented yby the feeder models depends
on the type of common treatment you want to apply to the feeder models. So there is
still the effort of applying the above shown changes to existing feeders.
Standard | Posted in Floorplan Manager | Tagged FPM, Wiring | 0 comments

12.28.12
by Uwe Kunath

PERFORM SAVE-OPERATIONS USING A WIRE


TRANSACTION HANDLER IN THE FPM

Introduction
In the previous blog post I figured out how wiring based on business objects might work
in the Floorplan manager. The example application provides a Search component to
select records based on the table SFLIGHT. Once a result entry has been selected, the
flight data record is shown in a detail view below the result list. While the result list is
implemented by a List-UIBB, the detail view is implemented by a Form-UIBB.
Any follow-up steps have not been implemented then, this includes also the possibility
to save the edited record back to the database.
The subject of this blog post is how a Save-operation could be implemented based on a
wire transaction handler.
I decided to not use the interface IF_FPM_TRANSACTION which can be implemented by
any UIBB in the application, rather, I decided to use a Transaction Handler for wire
models. The drawback of this approach is that a wire transaction handler cannot serve
as a target for wires, hence, has usually no access to Business objects.
One opportunity to pass the business object to the handler might be to share it as a
singleton instance. This requires the existence of a registry or any other singleton
mechanism. Another possibility is the data exchange based on events.
In this very blog post, the business object is going to be shared as a parameter of the
FPM_SAVE- event.
For now, lets again recap the wires which are in use by the demo application. However
besides this introduction it is strongly recommended to read the previous blog post if
you did not yet read it.

The existing application


The selection criteria and the selection of the flight list is implemented by the list
selection wire (ZCL_FPM_DEMO_WIRE_FLIGHT_SEL which implements

ZIF_FPM_DEMOWIRE_SFLIGHT_SEL).

The selected flight data record is represented by an instance of type


ZIF_FPM_DEMO_WIRE_SFLIGHT.

Both wires have specific operations offered to the UIBBs or OVP Exit which use these
wires.

In this blog post, the first wire is going to be extended to hold a lead selection instance
of the second wire. The second wire which represents a single flight data record will be
enhanced with a Save-operation. In combination with some other changes, this allows
the user to edit the flight data and save it back to the database.

Sharing the business object


A new Save-Button will be added to the applications OVP toolbar.
In order to allow the wire transaction handler to access the business object, the OVP exit
will catch the Save-Event which is triggered by the save- button and will enrich the
event data with a new Name-Value Pair which represents an instance of a saveable
business object, that is, the wire which represents a single entry of the flight data list (It
would be a good idea to work with an abstraction to the specific flight data instance as
well, so we can possibly reuse the wire transaction handler later on in another
application)
Since the OVP exit has access to the list selection instance only we need to provide
access to the selected business object through the list selection wire.

Enhancements to the current application

First of all, we include an OVP-toolbar button to allow the user to trigger the Saveoperation.

The list selection wire will need to store the selected flight record to allow the OVP Exit
to get access to the currently selected record. Therefore the methods
GET_LEAD_SELECTION and SET_LEAD_SELECTION are added to the interface
ZIF_FPM_DEMO_WIRE_FLIGHT_SEL which describes, what operations have to be
supported by this wire. In the implementing class, a new attribute MO_LEAD_SELECTION

is included and the corresponding Getter- and Setter method are implemented.

Now we need to call SET_LEAD_SELECTION in ZCL_FPM_DEMO_FLIGHT_LIST, method


IF_FPM_GUIBB_LIST~PROCESS_EVENT, which handles the lead selection event in the list.
METHOD if_fpm_guibb_list~process_event.
DATA lo_datacontainer TYPE REF TO zif_fpm_demo_wire_flight_sel

lo_datacontainer ?= mo_connector->get_output( ).
CASE io_event->mv_event_id.

WHEN 'FPM_GUIBB_LIST_ON_LEAD_SELECTI'.
CHECK lo_datacontainer IS NOT INITIAL.
READ TABLE mt_sflight INTO ls_sflight INDEX iv_lead_index.
IF sy-subrc = 0.
CREATE OBJECT mo_sflight TYPE zcl_fpm_demo_wire_sflight.
mo_sflight->set_sflight( ls_sflight ).
lo_datacontainer->set_lead_selection( mo_sflight ).
ENDIF.
ENDCASE.
ENDMETHOD.
The selected flight record is show in the detail section of the screen. Its feeder does not
yet have a FLUSH-implementation which needs to be implemented. Its purpose would
be to transfer the entered values back to the flight record instance.
Therefore the form feeder class ZCL_FPM_DEMO_FORM_SFLIGHT_DET receives a FLUSHmethod implementation:
METHOD if_fpm_guibb_form~flush.
CHECK mo_connector IS NOT INITIAL.
mo_sflight ?= mo_connector->get_output( ).
CHECK mo_sflight IS NOT INITIAL.

FIELD-SYMBOLS TYPE any.


ASSIGN is_data->* TO .
DATA ls_sflight_key LIKE ms_sflight.
MOVE-CORRESPONDING TO ms_sflight.
MOVE-CORRESPONDING TO ls_sflight_key.
ms_sflight-carrid = ls_sflight_key-carrid.
ms_sflight-connid = ls_sflight_key-connid.
ms_sflight-fldate = ls_sflight_key-fldate.
mo_sflight->set_sflight( ms_sflight ).
ENDMETHOD.
Now, the OVP exit has also access to the currently selected flight record instance
through its configured list selection wire. The OVP exit is implemented by the
webdynpro component ZWDYN_FPM_FLIGHT_OVP_EXIT. The implementation of method
OVERRIDE_EVENT_OVP now needs to try to read the flight record instance from the wire
model and enrich the Save-Event with the flight record data object. Please note that we
pass an instance of type ZIF_FPM_DEMO_SAVEABLE rather than
ZIF_FPM_DEMO_WIRE_SFLIGHT.
METHOD override_event_ovp.
wd_this->mo_ovp = io_ovp.
DATA lo_event TYPE REF TO cl_fpm_event.
DATA: lo_datacontainer TYPE REF TO zif_fpm_demo_wire_flight_sel,
lo_saveable TYPE REF TO zif_fpm_demo_saveable.
DATA lv_port_identifier TYPE fpm_model_port_identifier.
lv_port_identifier = zif_fpm_demo_wire_flight_sel=>gc_name.
lo_event = io_ovp->get_event( ).
CASE lo_event->mv_event_id.
WHEN if_fpm_constants=>gc_event-save OR if_fpm_constants=>gc_eventsave_and_back_to_main.
TRY.
lo_datacontainer ?= wd_this->mo_feeder_model>get_outport_data( iv_port_type = 'LS' iv_port_identifier =
lv_port_identifier ).
CHECK lo_datacontainer IS BOUND.
lo_saveable ?= lo_datacontainer->get_lead_selection( ).
lo_event->mo_event_data->set_value( iv_key =
zif_fpm_demo_saveable=>gc_event_parameter_id iv_value = lo_saveable ).
CATCH cx_sy_move_cast_error.
ENDTRY.
ENDCASE.
ENDMETHOD.
ZIF_FPM_DEMO_SAVEABLE serves as a generic interface for a save operation. It is
implemented by the wire which represents the flight record

(ZCL_FPM_DEMO_WIRE_SFLIGHT)

The class ZCL_FPM_DEMO_WIRE_MODEL_TRANS serves as the application wire


transaction handler. It implements the standard FPM interface
IF_FPM_WIRE_MODEL_TRANSACTION and therefore takes part in the event loop. The
method AFTER_PROCESS_EVENT is implemented and handles the SAVE-Event which will
later on be triggered once the Save-Button has been pressed. The method
implementation tries to read an instance of type ZIF_FPM_DEMO_SAVEABLE from the
event data and eventually call the SAVE-Method.
METHOD if_fpm_wire_model_transaction~after_process_event.
DATA: lo_savable TYPE REF TO zif_fpm_demo_saveable.
CASE io_event->mv_event_id.
WHEN if_fpm_constants=>gc_event-save OR if_fpm_constants=>gc_eventsave_and_back_to_main.
TRY.
io_event->mo_event_data->get_value(
EXPORTING iv_key = zif_fpm_demo_saveable=>gc_event_parameter_id
IMPORTING ev_value = lo_savable ).
CHECK lo_savable IS NOT INITIAL.
lo_savable->save( ).
CATCH cx_sy_move_cast_error.
ENDTRY.
ENDCASE.
ENDMETHOD.
Once the transaction handler class has been implemented, we register the transaction
handler in the OVP-Component FPM_OVP_COMPONENT, Configuration

ZFPM_DEMO_OVP_FLIGHT_SEARCH

Why should we not simply enhance the OVP-Exit?


The reason why I didnt just implement the Save-operation directly in the OVP-Exit is the
Separation of concerns design principle.
In the case of having an exit only and no transaction handler, the OVP Exit would have
to evaluate the save event and trigger the SAVE-Method, besides its task of updating
the OVP floorplan title with the number of results. Also, an OVP Exit is not reusable in
OIF or GAF floorplans, and this would also apply to its transaction logic, if coupled too
strongly.
Right now, with the current implementation, it only does, what an exit is intended to do:
It catches certain events like the Save-event and enriches it with some data, if
necessary. The actual SAVE-Method call is triggered by another component which
actually does not care about how or by whom the event has been enriched it just
expects the business object along with the event data. This decouples the execution of
the SAVE-Command from other aspects of the application and eventually leads to a
better design and maintainability. There is no real benefit yet, but in case a more
complex transaction logic would be needed, we could easily provide the implementation
of these aspects, like commits or rollbacks, in a specific transaction handler, not within
the OVP Exit.

WIRING BASED ON BUSINESS OBJECTS IN


FLOORPLAN MANAGER
Introduction
In my previous blog post I compared the main data exchange possibilities to share data
between UI Building Blocks (UIBBs) in the Floorplan Manager (FPM). The way of sharing
data supported by the FPM Framework is called Wiring. There are a lot of good guides

out there which show how wiring can be done. They usually utilize an example with a
list which sends the selected column to another UIBB to show some detail data.
The problem with these examples is usually not the wiring mechanisms of the FPM or
the way data is exchanged in general moreover the way it is implemented.
Usually, the examples include a wire which goes via Lead selection from a certain List
UIBB to a Form UIBB which shows the details of the record. The Wire connector contains
an attribute of a single record described purely by an ABAP structure. This is misleading
and is not the way large enterprise applications are implemented.
The problem with this approach is the fact that you are heading a dead end in most of
the cases: What can the Form UIBB, which shows the detail data of the record do with
the structure once there are some editable Input Fields showing the attributes of the
structure?
Well, data can be written back to the structure and then what? How can the record be
validated and saved on the database? If there is no function module to persist the data,
you would need to use ABAP OO, and in the cases where we ourselves use the FPM in
our own projects, there is always an ABAP OO Backend.
But you cant call operations on structures. So either the Connector, to which the Form
UIBB has access to, would have to persist the data afterwards or the Form UIBB would
have to create its instance of the Business Object by itself in order to call something like
a SAVE Method.
Both solutions arent really a good idea in terms of maintainability and
understandability. Thats why I wrote this blog post.

Demo
I set up a demo for this blog post in order to show the concepts which I used. The demo
application comprises the following functionality:

Search flights (implemented by a Search UIBB)

Show number of results in the header area (OVP Title)

Show a list of the results (implemented by a List UIBB)

Once the users selects an entry, a form UIBB shows the detail data

In order to make clear what the building blocks of the application are, I marked them for
you. Of course, the OVP Floorplan title is not a Building block, rather a part of the
header area of the OVP. For demo purposes, I also marked it since its information is also

getting updated, hence, subject to the wiring mechanisms I will show you in detail.

Data sharing
Sharing selection criteria and the result list
There are two UIBBs involved in sharing the selection criteria and result list with each
other. The header area of the OVP which shows the number of results is involved as
well. All of them share one object with each other which has the responsibility of
selecting all the data which fits to the selection criteria entered in the Search-Block.
The instance is typed as ZIF_FPM_DEMO_WIRE_FLIGHT_SEL. Please note that this is still
an interface which describes only what an object needs to do not how it is
implemented.
The reason why this interface inherits ZIF_FPM_DEMO, which contains no methods and
no attributes will be explained later on. There will be no further explanation here.

Wiring works based on this interface. Sharing the selection instance starts at the search
UIBB. It fetches the selection criteria and pushes it to the data selection instance
MO_CONTAINER of type ZIF_FPM_DEMO_WIRE.

METHOD if_fpm_guibb_search~process_event.
CLEAR: et_messages, ev_result.
DATA:
lt_selopt
TYPE if_powl_easy_feeder=>typ_t_selection_parameter,
ls_selopt
TYPE if_powl_easy_feeder=>typ_s_selection_parameter,
lt_sel
TYPE rsdsselopt_t.
FIELD-SYMBOLS:
<ls_sel>
TYPE rsdsselopt,
<ls_selcrit>
TYPE fpmgb_s_search_criteria.
DATA lo_cx_fpmgb TYPE REF TO cx_fpmgb.

DATA ls_message TYPE fpmgb_search_s_t100_message.


CASE io_event->mv_event_id.
WHEN if_fpm_guibb_search=>fpm_execute_search.
TRY.
LOOP AT it_fpm_search_criteria ASSIGNING <ls_selcrit>.
CLEAR ls_selopt.
APPEND INITIAL LINE TO lt_sel ASSIGNING <ls_sel>.
<ls_sel> =
cl_fpm_guibb_search_conversion=>to_abap_select_option( <ls_selcrit> ).
ls_selopt-attribute = <ls_selcrit>-search_attribute.
ls_selopt-sign
= <ls_sel>-sign.
ls_selopt-option
= <ls_sel>-option.
ls_selopt-low
= <ls_sel>-low.
ls_selopt-high
= <ls_sel>-high.
APPEND ls_selopt TO lt_selopt.
ENDLOOP.
CATCH cx_fpmgb INTO lo_cx_fpmgb.
ls_message-plaintext = lo_cx_fpmgb->get_text( ).
ls_message-severity = if_fpm_message_manager=>gc_severity_error.
APPEND ls_message TO et_messages.
ENDTRY.
mo_container->set_selection_criteria( lt_selopt ).
ENDCASE.
ENDMETHOD.
If the instance does not yet exist, it is created at runtime during the wiring setup.
METHOD if_fpm_feeder_model~get_outport_data.
try_get_container( ).
CASE iv_port_identifier.
WHEN zif_fpm_demo_wire_flight_sel=>gc_name.
ro_data = mo_container.
ENDCASE.
ENDMETHOD.
METHOD try_get_container.
CHECK mo_container IS INITIAL.
IF mo_connector IS NOT INITIAL.
mo_container ?= mo_connector->get_output( ).
ELSE.
CREATE OBJECT mo_container TYPE zcl_fpm_demo_wire_flight_sel.
ENDIF.
ENDMETHOD.
Targets are both the List UI Building Block as well as an OVP Exit (which implements
IF_FPM_OVP_CONF_EXIT) which is also implementing the Application Controller Interface
(IF_FPM_APP_CONTROLLER) and the UIBB feeder model interface (IF_FPM_UIBB_MODEL).
This way it can also serve as a target for wiring. This OVP Exit updates the Application
header title.
The list UIBB accesses the instance via the connector which has been passed by the
FPM framework during wiring setup.
DATA lo_datacontainer TYPE REF TO zif_fpm_demo_wire_flight_sel.
CASE io_event->mv_event_id.
WHEN if_fpm_guibb_search=>fpm_execute_search.
lo_datacontainer ?= mo_connector->get_output( ).

lo_datacontainer->apply_selection( ).
mt_sflight = lo_datacontainer->get_list( ).
...
ENDCASE.
The OVP Exit receives the instance via its feeder model and hooks into the
AFTER_PROCESS_EVENT-Method:
METHOD after_process_event .
DATA lo_ovp TYPE REF TO if_fpm_cnr_ovp.
lo_ovp ?= wd_this->mo_fpm>get_service( cl_fpm_service_manager=>gc_key_cnr_ovp ).
DATA lo_datacontainer TYPE REF TO zif_fpm_demo_wire_flight_sel.
DATA lv_port_identifier TYPE fpm_model_port_identifier.
DATA lv_title TYPE string.
DATA lv_num TYPE i.
DATA ls_content_area TYPE if_fpm_ovp=>ty_s_content_area.
CHECK wd_this->mo_feeder_model IS NOT INITIAL.
lv_port_identifier = zif_fpm_demo_wire_flight_sel=>gc_name.
lo_datacontainer ?= wd_this->mo_feeder_model>get_outport_data( iv_port_type = 'LS' iv_port_identifier =
lv_port_identifier ).
ls_content_area = lo_ovp->get_current_content_area( ).
CHECK: lo_datacontainer IS NOT INITIAL, lo_ovp IS NOT INITIAL.
lv_num = lo_datacontainer->get_number_of_results( ).
lv_title = lv_num.
CONCATENATE 'Flight Search -' lv_title 'results' INTO lv_title SEPARATED
BY space.
ls_content_area-title = lv_title.
lo_ovp->change_content_area_restricted( iv_content_area_id =
ls_content_area-id iv_title = lv_title ).
ENDMETHOD.

The wiring setup finalizes the implementation and makes clear what the data exchange
directions are. The connector class which is used for that is
ZCL_FPM_DEMO_FL_SEARCH_CONN. There will be two wires as both the flights result list
as well as the OVP title need to be updated based on the flight results.
It contains an instance of type ZIF_FPM_DEMO_WIRE, the parent interface of the current
business objects interface.

Sharing the selected entry as a business object


The List UIBB which shows the flight results needs to setup another business object
which does not contain a list of flights, rather the exact record, which has been selected
by the user. The flight record is represented by an instance of type
ZIF_FPM_DEMO_WIRE_SFLIGHT. It inherits from ZIF_FPM_DEMO as well as the previously
introduced business object of type ZIF_FPM_DEMO_WIRE_FLIGHT_SEL.

The business object currently only provides a Setter and a getter method to read the
data structure or write a modified data structure back to the instance.

The wiring setup reuses the connector class ZCL_FPM_DEMO_FL_SEARCH_CONN as there


is no special treatment needed for the exchange of the current business object.
As mentioned earlier, it contains an instance of type ZIF_FPM_DEMO_WIRE, the parent
interface of both business objects interfaces.
Now it is getting clear, what ZIF_FPM_DEMO_WIRE is used for. It is just a marker
interface, which gives a hint, which business objects are shared across the application.
As the connector references an instance of that type, it can be referencing both the
selection as well as the flight record. There is no technical or functional requirement for
that the reason why I didnt use a more generic REF TO OBJECT for the instance is the
fact that I just wanted to make clear for someone who reads and needs to understand
the code, what the intended context of the current connector is.

I didnt implement any update operations for this demo, but it would be yet another
method for the existing business object besides the SET_SFLIGHT( )-Method, for
example SAVE( ).
Since the feeder has already access to the wired business object, it has also access to
its public methods. The SAVE( )-method would implement the update operations and
could be called directly from the form feeder which provides the UI operations for the

flight details building block.


In contrast to a possible solution, where only a flat data structure was exchanged, this is
a much more convenient way of accessing and modifying the data provided by the
backend.
Code nugget
NUGG_FPM_DEMOV4.nugg

DATA EXCHANGE POSSIBILITIES IN


FLOORPLAN MANAGER
Introduction
The Floorplan Manager (FPM) allows you to separate UI components into distinct
building blocks which can be arranged to an entire application. These UI building blocks
(UIBBs) may also be reusable in order to use them later on in another scenario. But
without exchanging data, only few UIBBs can be properly used. So data sharing between
certain UI components is a common requirement, not only in FPM based applications.
There are a lot of good guides in SCN which deal with the question of how data can be
exchanged between UIBBs in the FPM.
So initially this blog post wouldnt be necessary at all and I could have saved my time.
The reason why I didnt, is the fact that none of these blogs deal with the question, what
the drawbacks of each approach are and what would be the specific difficulties to deal
with in an evolving architecture during the implementation of large enterprise
applications.

Options of sharing data between UIBBs


To share data between UIBBs in the FPM, there are mainly three options:

Singleton

Events

Wiring

Shared Data component (not usable for Generic UI Building Blocks)

Each of these options will be described below.

The Shared Data Component


Freestyle UIBBs can implement the Webdynpro Component interface
IF_FPM_SHARED_DATA. The context of this component can be mapped in any other

Freestyle UIBB. Since context mapping is not possible for the Generic UIBBs, I do not
further investigate this possibility.

The Singleton-based approach


How does it work
This approach is quite easy to implement. Every UIBB or every OVP-/OIF-/GAF-Exit gets
an instance of the application model by calling a static method of the class which
implements this application model.
method IF_FPM_GUIBB~INITIALIZE.
mo_application_model = zcl_fpm_demo_application_model=>get_instance( ).
endmethod.
This call will return the same instance at every call. This means, any method and any
data will be read from and written to the same instance. This approach is the easiest
and one of the more dangerous approaches in terms of maintenance requirements

Advantages

Easy to implement

Easy to implement also in dynamic scenarios, where UIBBs are registered at


runtime

Sharing of a single Instance which offers both data and operations to its
clients is quite easy, there is no need to share only internal tables or
structures which offer no follow-up operations for the UIBBs dealing with
these data structures / instead, UIBBs can get an object, retrieve data and
also write some data back based on what the UIBBs was intended to do

Drawbacks

While in the standard FPM configuration editor, there is no transparency


how an UIBB exchanges its data

All UIBBs which rely on the application model class will work only with this
class, hence, show a strong association with that class. This threats the
reusability of that components in scenarios which usually do not deal with
this very application model class

This issue can be minimized by having multiple singleton instances


(application models) which share some data between each other based on
generic dependency injections. This could be achieved by using Constructor
Injections or Setter Injections of the corresponding application models.
However, the outcome will be multiple classes whose dependencies would
have to be managed separately in an extra FPM component, e.g. the
application controller. To resolve dependencies, tools like IoC Container
might help but anyway, you need to be absolutely clear about the

application model before starting with a singleton based approach. It is easy


to implement at the beginning but might turn out to a maintenance monster
if you forget to care about it.

Specific UIBBs cannot be adressed conditionally this way. If you do not


separately implement some logic which prevents certain UIBBs from getting
updates based on the application model, all UIBBS which look for the
corresponding model will get and write data from/to it or will not.

The Event-based approach


How does it work
Imagine a Search UIBB which works based on the table SFLIGHT needs to propagate its
selection criteria to other UIBBs when the user pressed Search. If data exchange was
implemented by a Singleton class, the method if_fpm_guibb_search~process_event
would try to get the singleton instance and share the selection criteria by calling a
method call which might look like this
lo_singleton->SET_FLIGHT_SELECTION_CRITERIA( lt_selopts )
In contrast to sharing the data using a singleton instance, the UIBB could also re-raise
the event by actually triggering a new event with event parameters:
METHOD if_fpm_guibb_search~process_event.
...
DATA lo_fpm_parameter TYPE REF TO if_fpm_parameter.
DATA lo_fpm TYPE REF TO if_fpm.
* get FPM
lo_fpm = cl_fpm_factory=>get_instance( ).
* raise apply selection event
lo_fpm_parameter = cl_fpm_parameter=>create_by_lpparam( it_parameter =
lt_parameter ).
lo_fpm_parameter->set_value( iv_key = 'SEARCH_CRITERIA_FLIGHTS' iv_value =
IT_FPM_SEARCH_CRITERIA ).
lo_fpm->raise_event_by_id(
iv_event_id = 'ON_SEARCH_FLIGHTS'
io_event_data = lo_fpm_parameter ).
...
ENDMETHOD.
Any UIBB which is interested in getting the selection criteria should handle this event in
its own PROCESS_EVENT method. Any kind of the OVERRIDE-Methods which are used by
certain exits are also welcome.
DATA: lr_data TYPE REF TO data.
CASE io_tabbed->mo_event->mv_event_id.
WHEN 'ON_SEARCH_FLIGHTS'.
FIELD-SYMBOLS <lt_selopts> TYPE FPMGB_T_SEARCH_CRITERIA.

io_tabbed->mo_event->mo_event_data->get_value(
EXPORTING iv_key = 'SEARCH_CRITERIA_FLIGHTS'
IMPORTING er_value = lr_data ).
ASSIGN lr_data->* TO <lt_selopts>.
...
ENDCASE.

Advantages

Easy to implement
Easy to implement also in dynamic scenarios, where UIBBs are registered at
runtime
No extra class for the backend object needed

Drawbacks

No transparency while in the configuration editor, how an UIBB exchanges


its data

Danger of creating endless loops caused by cascading event raisings


without having a chance of knowing it when in a certain feeder class.
Example: This could happen if UIBB 1 triggers an event which is handled by
UIBB 2. UIBB 2 in triggers another event itself which is handled by UIBB 3.
This component could also trigger its own events, which could eventually
cause UIBB 1 to start the event loop again.

only visible UIBB take part in the event loop, invisible UIBBS (e.g. in other
tabs than the currently selected tab) do not receive the data

You cannot address specific UIBBs this way, instead all visible UIBBS take
part in the event loop and will handle this event or ignore it

The parameter signature of the events might change without notice, or


worse, another UIBB which raises the same event uses the same parameters
but with another type. This aint fun for the clients of these events

The Wiring-based approach


How does it work
Wiring is the standard FPM-concept to share data. Im not going to explain it here.
Instead I refer to help.sap.com, the FPM developer guide, or the official book
There are also guides in SCN which describe wiring based on structures or tables.

Advantages

Since the connector classes and the data which they provide are defined at
design time and used both on sender and receiver side, surprises are less
certain than in the event-based approach. However, a sender might still

decide to return different data via its outports which will cause an error at
runtime

This little disadvantage brings us to the next advantage: Wiring can be


configured in the FPM configuration editor. Errors can be found much quicker
since every data exchange needs to be registered here

This also makes transparent, which data the UIBB you are currently
configuring, really uses

Drawbacks

It is very difficult to implement wiring in dynamic scenarios, where UIBBs


are added at runtime

This drawback is not mentioned because of the wiring concept, rather


because of the way it is commonly used: Developers tend to share structures
and tables between UIBBs without the possibility to support follow-up
operations since these still remain simple data objects, but no object
instances. Sharing application models between UIBBs is a much more
powerful possibility which I might demonstrate in an upcoming blog

Compared to the other options it is the most complicated approach and


might be hard to follow and implement for someone who is new to FPM
development

Conclusion
Every approach has its specific advantages. What we learned in real implementation
projects, is, that there is always a mixture of these approaches depending on the
scenario and the requirements in terms of reusability of UIBBs. If your UIBBs need to be
reusable in various scenarios the approaches to exchange data should be (in order of
relevance): Wiring before Singleton before Events.

You might also like