Skip to Content

Part 1: Decision to use WD4A

Similar to Practical tips for developing with ABAP WebDynpro I had tinkered with WD4A in training environments for some twelve months going through the various tutorials on SDN during any spare downtime between projects. I had bought the SAP Press book by Ulli Hoffmann which all seemed quite straight forward when taking individual examples in isolation.

To my delight the next project was to be an ESS/MSS implementation on ECC6. Having gone through the blueprint it was obvious that a number of new applications needed to be written to meet the business requirement. This gave rise ‘to WD4A or not to WD4A’ – that was the question.

After reading many articles on the subject including the one by Web Dynpro: ABAP or Java? I decided that the plan for any new applications would be WD4A and not Java WebDynpro. The main reasons for this decision were:

  • Content of the applications were based purely on ECC6 data i.e. all the application logic is based upon an ABAP system
  • No need to setup NWDI/NWDS (no plans to modify the existing delivered applications)
  • UI elements included ALV for some reporting requirements
  • Tools for development were more familiar
  • Support of the solution would be easier as the skill set available was primarily ABAP based

More importantly it gave me the perfect opportunity to put my skills into practice by having true productive developments to write!

Part 2: Design Principles

Now came the tricky bit. Developing productive applications is a far cry from prescriptively following examples on SDN. From the blueprint it was obvious that a sensible and consistent approach was needed if my applications were to have a look and feel of the standard SAP content for ESS/MSS.

Searching through SAP content and SDN I realised that ESS/MSS applications are built on a concept called the Floor Plan Manager (FPM).  However, this is for Java WebDynpro and not WD4A.  However, it did give an overall framework for how the applications look and feel. 

This is especially highlighted in the document ‘ESS & WebDynpro’ by Ralf Halbedel and Dr. Christian Wiele.  In particular this defined the general visual steps that each application has. The application views would be based upon a roadmap area, a message area and a context area.

Part 3: Development

With a basic understanding of the Java FPM I wanted to re-create a similar appearance to my applications. However, as with all custom development there needs to be a trade off between a completely flexible solution and one that offers a degree of flexibility whilst maintaining readability for support purposes.
With this in mind I decided to split the framework into several components that could be reused in each application. The following sections give an understanding as to what these components consist of. As with all custom development there are several ways to achieve the same result. Ultimately this may not be the best way – after all this is a leap of faith from the comfort of examples into the ‘real world’ of WD4A development…..

Part 4: Roadmap UI Component

One of the fundamental UI elements in ESS/MSS is the Roadmap. This was an immediate candidate for component reuse. As each application would be different there needed to be a way to configure the roadmap and build it up dynamically. In addition this needed to interact with some navigation buttons to move the user through the application.

The first step was to define a table to hold the steps for each application. This consisted of a main table and a language dependant table to hold the descriptions.

Table for application steps

Step Table

Table for application step descriptions

Step Descriptions

A corresponding maintenance view was created to allow the application developer to make entries.

Next a roadmap WD component was needed to visualise the steps in the table.  The component simply consisted of a single view with the UI element ‘RoadMap’.

FPM RoadMap Component 

FPM UI

FPM RoadMap View 

FPM View

FPM Roadmap Controller Context

FPM Context

Note that the context has been defined as as interface node and Input Element (Ext.) so that it can be controlled via the using component.  The fields themselves are based upon a dictionary structure of the corresponding transparent table that defines the steps.

Next the individual steps needed to be created dynamically.  This was done in the method WDDOMODIFYVIEW

METHOD wddomodifyview .
DATA:
  node_steps TYPE REF TO if_wd_context_node,
  table_steps TYPE if_v_rm_ui=>elements_steps,
  stru_steps TYPE if_v_rm_ui=>element_steps,
  lr_rm TYPE REF TO cl_wd_road_map,
  lr_rm_step TYPE REF TO cl_wd_road_map_step,
  ls_step TYPE string,
  ls_step_ltext TYPE string,
  ls_step_id TYPE string.
  CHECK first_time = abap_true.
* get roadmap element
  lr_rm ?= view->get_element( 'ROAD_MAP' ).
* get steps from context to dynamically create
  node_steps = wd_context->get_child_node( name = if_v_rm_ui=>wdctx_steps ).
  node_steps->get_static_attributes_table( IMPORTING table = table_steps ).
* add each step as defined in attribute gt_steps in the controller
  LOOP AT table_steps INTO stru_steps.
    ls_step = sy-tabix.
    ls_step_ltext = stru_steps-ltext.
    ls_step_id = stru_steps-stepid.
*   create step
     lr_rm_step = cl_wd_road_map_step=>new_road_map_step(
       description         = ls_step_ltext
       id                  = ls_step_id
       name                = ls_step ).
*   add step to roadmap
    lr_rm->add_step( lr_rm_step ).
  ENDLOOP.
ENDMETHOD.

Now that the steps have been created there needs to be a mechanism to move between steps.  In order to do this a new interface method has been defined in the component controller. This method has an input parameter of DIRECTION i.e. PREVIOUS or NEXT.

METHOD set_next_step .
  DATA lc_plug TYPE string VALUE 'TO_'.
  DATA li_index TYPE i.
  DATA lo_nd_steps TYPE REF TO if_wd_context_node.
  DATA lo_el_steps TYPE REF TO if_wd_context_element.
  DATA ls_steps TYPE wd_this->element_steps.
  wd_this->set_roadmap_step( i_direction ).
  lo_nd_steps = wd_context->get_child_node( name = wd_this->wdctx_steps ).
  li_index = lo_nd_steps->get_lead_selection_index( ).
  lo_el_steps = lo_nd_steps->get_element( li_index ).
* get all declared attributes
  lo_el_steps->get_static_attributes( IMPORTING static_attributes = ls_steps ).
  CONCATENATE lc_plug ls_steps-stepid INTO lc_plug.
  wd_this->fire_next_step_evt( lc_plug ).
ENDMETHOD.
METHOD set_roadmap_step .
  DATA:
    node_steps TYPE REF TO if_wd_context_node,
    li_step    TYPE i.
* read component
  node_steps = wd_context->get_child_node( name = if_componentcontroller=>wdctx_steps ).
  li_step = node_steps->get_lead_selection_index( ).
* set new step number
  CASE i_direction.
    WHEN zcl_ess_assist=>fpm_step_next.
      li_step = li_step + 1.
    WHEN zcl_ess_assist=>fpm_step_prev.
      li_step = li_step - 1.
  ENDCASE.
* reset lead selection to new step
  node_steps->set_lead_selection_index( li_step ).
ENDMETHOD.

The interface method will set the lead selection according to whether the user pressed the PREVIOUS or NEXT button.  In addition the method will fire an interface event that contains a parameter of the navigation plug to be fired based upon a simple concatenation of the step. 

BTW: the reference to ZCL_ESS_ASSIST contains some public static constants that are used throughout the application(s).

Part 5: Button Row UI Component

The second reusable component is the button row.  This needs to work in conjunction with the RoadMap component to provide the necessary events to move through the application steps.

FPM ButtonRow Component

FPM BR Component

FPM ButtonRow View

BR Layout

FPM ButtonRow Context

FPM BR Context

The STEPS_EXTERNAL context node is the same as defined in the RoadMap component so that the button descriptions can be picked up for the correct step.

The buttons are connected to ONACTION events that will fire an interface event:

METHOD onactionnext .
  wd_comp_controller->set_button_event( zcl_ess_assist=>fpm_step_next ).
ENDMETHOD.
METHOD onactionprev .
  wd_comp_controller->set_button_event( zcl_ess_assist=>fpm_step_prev ).
ENDMETHOD.
METHOD set_button_event .
  DATA lo_nd_steps_external TYPE REF TO if_wd_context_node.
  DATA lo_el_steps_external TYPE REF TO if_wd_context_element.
  DATA ls_steps_external TYPE wd_this->element_steps_external.
* get current step details
  lo_nd_steps_external = wd_context->get_child_node( name = wd_this->wdctx_steps_external ).
  lo_el_steps_external = lo_nd_steps_external->get_element( ).
  lo_el_steps_external->get_static_attributes( IMPORTING static_attributes = ls_steps_external ).
* trigger interface event
  wd_this->fire_action_br_evt( EXPORTING e_step = ls_steps_external
  e_direction = i_direction ).
ENDMETHOD.

In addition a number of interface methods have been defined in the component controller.  These methods allow the button row to be controlled via the calling component.

METHOD set_button_row_enabled .
  DATA lo_nd_button_row TYPE REF TO if_wd_context_node.
  DATA lo_el_button_row TYPE REF TO if_wd_context_element.
  DATA ls_button_row TYPE wd_this->element_button_row.
* navigate from to via lead selection
  lo_nd_button_row = wd_context->get_child_node( name = wd_this->wdctx_button_row ).
  lo_el_button_row = lo_nd_button_row->get_element( ).
* get context
  lo_el_button_row->get_static_attributes( IMPORTING static_attributes = ls_button_row ).
* change single attribute
  ls_button_row-enabled = i_enabled.
* reset context
  lo_el_button_row->set_static_attributes( EXPORTING static_attributes = ls_button_row ).
ENDMETHOD.
METHOD set_button_row_visible .
  DATA lo_nd_button_row TYPE REF TO if_wd_context_node.
  DATA lo_el_button_row TYPE REF TO if_wd_context_element.
  DATA ls_button_row TYPE wd_this->element_button_row.
* navigate from to via lead selection
  lo_nd_button_row = wd_context->get_child_node( name = wd_this->wdctx_button_row ).
  lo_el_button_row = lo_nd_button_row->get_element( ).
* get context
  lo_el_button_row->get_static_attributes( IMPORTING static_attributes = ls_button_row ).
* change single attribute
  ls_button_row-visible = i_visible.
* reset context
  lo_el_button_row->set_static_attributes( EXPORTING static_attributes = ls_button_row ).
ENDMETHOD.

These methods were necessary as in some applications a button row may need to be disabled or set invisible as determined by the calling application.

Part 6: Bringing it all together

Now that the main reusable components have been created they can be consumed by an application.  Following the FPM of standard SAP applications the WD4A application consists of the following main view:

Application

The main view of the application is split into a roadmap area, message area, application area (as per the individual application needs) and a button row area.

In this example the application has three steps

Demo Application

Each step is embedded into the VCU_APPL container.  In addition each step has a corresponding inbound plug defined:

Demo Inbound Plug

The main view then controls all the navigation between steps by defining corresponding outbound plugs.  These plugs are the ones that are fired by the RoadMap component.

Demo Main Plugs

The window then connects the plugs accordingly

Demo Window Plugs

To bind all this together the application needs to select the steps as defined in the table (see Part 4).  This can be done somewhere in the WDINIT method of the COMPONENT CONTROLLER using syntax such as

DATA lo_application TYPE REF TO if_wd_application.
DATA lo_application_det TYPE REF TO if_wd_rr_application.
DATA lo_api_componentcontroller TYPE REF TO if_wd_component.
DATA lo_cmp_usage TYPE REF TO if_wd_component_usage.
* get application name
  lo_api_componentcontroller = wd_this->wd_get_api( ).
  lo_application = lo_api_componentcontroller->get_application( ).
  lo_application_det = lo_application->get_application_info( ).

Capturing the ButtonRow Event

When the user presses the PREVIOUS or NEXT button then the event raised can be listened for in each individual view of the application.

View event

The receiving event can then process the screen and determine if the next view should be displayed (e.g. by checking mandatory fields etc).

METHOD do_handle_br .
DATA lo_api_controller TYPE REF TO if_wd_view_controller.
  CHECK e_step-stepid = 'STEP1'.
* do your stuff
  CASE e_direction.
    WHEN zcl_ess_assist=>fpm_step_prev.
    WHEN zcl_ess_assist=>fpm_step_next.
*    e.g. check mandatory fields in this view
  ENDCASE.
  wd_comp_controller->set_next_step( e_direction ).
ENDMETHOD.

If the application is allowed to navigate to another view then the next step can be executed.

METHOD set_next_step.
DATA lo_interfacecontroller TYPE REF TO ziwci_ess_fpm_rm_ui . 
  lo_interfacecontroller = wd_this->wd_cpifc_usage_rm( ).
  lo_interfacecontroller->set_next_step( i_direction ).
ENDMETHOD.

This will call the interface method of the RoadMap component (see method METHOD set_next_step in Part 4).

Finally in the component controller of the application a listening event is defined.

RoadMap Event Handler

This method now needs to call another method within the main view.  In order to do this another event is fired.

METHOD do_handle_next_step .
  wd_this->fire_do_navigation_evt( e_new_step ).
ENDMETHOD.

The receiving method as defined in the MAIN view will fire the necessary navigation plug.

Main View Event Handler

METHOD do_handle_next_step .
  DATA lr_view_ctr TYPE REF TO if_wd_view_controller.
  lr_view_ctr = wd_this->wd_get_api( ).
  CALL METHOD lr_view_ctr->fire_plug( EXPORTING plug_name = e_new_step ).
ENDMETHOD.

Part 7: The Finished Application

The following screen shots show the finished article as seen by the ESS/MSS user.  Note the configuration of the buttons in terms of visibility and descriptions.

Configuration Steps

Step 1

Config 1

Step 2

Config 2

Step 3

Config 3

Application Steps 

Note that ‘Step 1, Step 2 and Step 3’ are the application component views as defined in the VCU_APPL UI element of the main view.

Step 1

Step 1

Step 2

Step 2

Step 3

Step 3

Part 8: Conclusion

At first glance this may seem rather complicated.  However, by designing the RoadMap and ButtonRow UI elements as reusable components saved considerable time in developing the individual applications.  This concept can be used for any WD4A application and not just specific to ESS/MSS. 

Personally it brought me a step further towards understanding the WebDynpro framework by having practical uses for concepts such as reverse context mapping, component usages, event handling and dynamic UI programming.  By bringing these together the end user of the system has a consistent look and feel to their applications regardless of them being standard content or bespoke.

As stated upfront there are several ways to approach custom development. I have learnt that the best way to develop WD4A is by designing small components that can interact with each other through simple reverse context mapping, interface methods and interface events.

To report this post you need to login first.

8 Comments

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

  1. John Patterson
    Hi Pete
    I really like the PCUI floorplan, I have written various custom JAVA WD applications with it and found it very powerful. I have always wondered why the ABAP version hasn’t been made available in all systems and promoted as bespoke development environment.

    I hope you keep us posted on how the framework evolves, may I suggest you continue using the Java version as a reference and adopt the
    – Visual Component
    – Faceless Component
    – facade
    – existing logic
    approach as illustrated on page 13 of the ESS & Webdynpro. Separating the webdynpro components and model services further may seem like a lot of work to begin with, but will prove extremely effective in the long run if you chose to develop large applications.

    Cheers
    jsp

    (0) 
    1. Pete Devereux Post author
      Hi John,

      Thanks for your comments.  As you say it’s a pity there is not an equivalent framework in WD4A yet and that it is left up to the individual developer to create their own interpretation.

      What I did not really explain (information overload) is how I used my FPM object to retrieve attributes about the employee together with the application steps (as per the Perspectives layer in the ESS & WebDynpro guide). 

      I tried to follow the Java model by extracting all business logic into separate model classes so they could be reused as part of a different UI if required in future.  This worked quite well as some of the model classes were used as part of workflow processing.

      What I want to do next is take the framework one step further and have a better separation of the visual layer.  Hopefully this would mean simply plugging in the visual aspects of an individual application and letting the framework handle the rest.

      At the time of writing this was the trade off between a complete generic framework solution and a half-way house.

      Cheers,
      Pete

      (0) 
    1. Pete Devereux Post author
      Hi Ian,

      Unfortunately I started the development circa 5 months ago where I found no evidence of a WD4A FPM version – therefore decided to write a pseudo one myself. However, now you have pointed out the work being done by Ed Herrmann then I will follow it with great interest.  Hopefully their good work will wing it’s way to Berlin.

      As for the SAPLink version – I will try and package it up sometime and place on the appropriate Wiki.

      Cheers,
      Pete

      (0) 
      1. Ian Stubbings
        Hi Pete

        I will hopefully implement your solution in the near future anyway as it may be while before we get on the new pack. There are a few concepts such as the reverse context mapping that will be good to get to grips with.

        Cheers
        Ian

        (0) 
  2. Ritin Jain
    Hi,

    The following link is missing. Can you please update the same. 

    ‘ESS & WebDynpro’ by Ralf Halbedel and Dr. Christian Wiele.

    Many Thanks!
    Ritin

    (0) 

Leave a Reply