Using Web Services

Introduction

Web services allow you to connect ABAP (or other) application functionality directly to your form, or directly to your FLM user exits.  If you already have a wsdl (Web Service Description Language) that you've downloaded from say Google, you can just import that into your forms as described in the developer guide.

If you have an ABAP function module you do the following to convert to a Web-service interface then follow the SOA runtime setup as described in the Web Services Config and Create wiki.

Heartbeat Web Service example gives a complete guide on of how to create, test and use a Web Service.

Also an example of  How to Consume an External Web Service via an ABAP Proxy Class.

Authorization for Web Services in HTML Forms.

For web services in HTML forms there is an additional check against standard SAP object S_DEVELOP and S_SERVICE depending on user activity for the name of the service being called. The PDF process did not make this check so a new authorization is required for all users likely to call the Z web services.

Find more details in the FLM Authorizations and Security documentation.

Transporting Web Services

As of FLM 295 SP1 WSDLs hosted on the local system to FLM are automatically updated at runtime.

The WSDL still must to be published using the same name using the WSDL Wizard and configured in SOAMANAGER in each system in the landscape as described below using the usual SAP tools. But, importing of the .wsdl and binding only needs to be done in DEV and the form transported across the landscape using the FLM Transport Wizard. 

In NW 702 the end points  no longer auotmatically get generated in QA and PRD when transported and must be added in SOAMANAGER. The end points must have the exact same names in DEV,QA,PRD for the FLM Rehosting routines to work.

The WSDL must be published from the same SAP Client that FLM will be used. For example if the FLM Portal is configured to use Client 400 than the WSDL must also be published from Client 400.

//Note: If the WSDL URL is incorrectly substituted in the Form at runtime with a SAP URL check to ensure that the table httpurlloc is empty.

How to Publish a Function Module as a Web Service

To turn a Function Module into a Web Service (.wsdl) do the following:

  • Make the Function Module RFC enabled on the Attributes tab in SE37,
  • you may also need to change your parameters to "call by reference" if necessary
  • Then in the menu select /utilities/more utilities/create web service/from the function module
  • Follow the wizard through it provides details at each screen.
  • Transaction SOAMANAGER, this launches a browser session.  Log in as an Administrator.
  • Tab ‘Business Administration’ or 'Single Service Administration', choose ‘Web Service Administration’
  • Enter a Search pattern and click Go
    • for example, to search for Z* function modules enter Z*)
  • Click on row needed, click ‘Apply Selection’
  • If you need the WSDL file for import into Designer, do the next 2 steps:
    • Click on ‘Open WSDL document for selected binding’, this launches a new web page
    • Right click on web page, choose View source.  Save file as ‘MYWEBSERVICE.wsdl’ – this is what you need to import into Designer
  • Back to SOAMANAGER screen, choose Configurations tab.
  • Choose Webservice, click Edit
    • As of NW 702 the end point may not exist and must be manually created. The end point names must be exactly the same in DEV,QA,PRD in order for the FLM Rehosting routine to work.
  • Enter ABAP service user/password at the bottom, click Save
    • In NW 702 selecte "No Authorization" in the "Provider Security" tab to get the user/password fields.

Designer-based web services (Client-side Web services)

Web Services can be accessed via the data connection functionality in Adobe Designer. You need a .wsdl file to do this which is generated after you have web-enabled an ABAP function module and done the Web Services administration steps (Web Services Config and Create).

From Designer, Data View, Right click and then New Data Connection, WSDL file, Next and select the location of the required file.

Bind the import and export parameters to your screen fields as required, then add the following line of code into the triggering event you require (this can be anywhere, make sure it's java script at client):

1:
2:
3:
xfa.connectionset.<Web service name>.execute(false);
//or 'true' if its a repeating section, this triggers a re-merge of the data,
//so 'false' by default for performance reasons

FLM-based Web Services (ie server side Web Services)

If you wish to consume an externally based web-service via ABAP proxies, please see here.  The main article here is a specific case of this for a particular web service.

FLM ships with a VAT registration validation web service stored in class /FLM/WS_LIB_1.  This webservice can be invoked from any ABAP user exit and requires the SAP server to have www access at the moment of processing.  Also you must have done the SOA technical set up (Web Services Config and Create).  The client side proxy (available in SE80) is called /FLM/CO_CHECK_VAT_PORT_TYPE.

To make use of this web service, you will need to

  1. create two fields on the form: one into which the VAT country code is entered, and one to contain the VAT number itself. Call these fields “COUNTRY” and “VAT_NUMBER”.
  2. Create a third field, called ‘IS_VALID’, type = checkbox, and assign it a derivation routine
  3. In the field-level derivation userexit on the IS_VALID field, enter the following code behind the derivation userexit:
    1. 1:
      2:
      3:
      4:
      5:
      6:
      7:
      8:
      9:
      10:
      11:
      12:
      13:
      14:
      15:
      16:
      17:
      18:
      19:
      20:
      21:
      22:
      23:
      24:
      25:
      26:
      27:
      28:
      29:
      30:
      31:
      32:
      33:
      34:
      35:
      36:
      37:
      38:
      39:
      40:
      41:
      42:
      43:
      44:
      45:
      46:
      47:
      48:
      49:
      50:
      51:
      52:
      53:
      54:
      55:
      56:
      57:
      58:
      59:
      60:
      61:
      62:
      63:
      64:
      65:
      66:
      67:
      68:
      69:
      70:
      
          DATA:  l_country(2) TYPE c,
          l_vat_number TYPE string,
          l_data       TYPE /flm/xml_tab,
          l_valid      TYPE flag,
          l_message    TYPE string,
          l_var        TYPE symsgv,
          l_v1         TYPE symsgv,
          l_succ_mess  TYPE string.
          *
          CLEAR: l_country,
          l_vat_number,
          l_valid,
          l_message.
      
          READ TABLE im_data INTO l_data WITH KEY name = 'COUNTRY'.
          l_country = l_data-value.
      
          *
          READ TABLE im_data INTO l_data WITH KEY name = 'VAT_NUMBER'.
          l_vat_number = l_data-value.
      
          *
          CHECK l_country IS NOT INITIAL AND
          l_vat_number IS NOT INITIAL.
      
          *
          CALL METHOD /flm/ws_lib_1=>eu_vat_registration_check
              EXPORTING
                im_country_code = l_country
                im_vat_number   = l_vat_number
                im_port_name    = 'DEFAULT'
              IMPORTING
                ex_valid        = l_valid
                ex_message      = l_message.
          *
          * Dispatch log message
          *
      
      
          IF l_message IS NOT INITIAL.
          MOVE l_message(20) TO l_succ_mess.
          ELSE.
          IF l_valid IS INITIAL.
          MOVE 'Not Valid ' TO l_succ_mess.
            ELSE.
          MOVE 'Valid' TO l_succ_mess.
            ENDIF.
          ENDIF.
          *
          CONCATENATE 'EU VAT check for' l_country '/' l_vat_number ':' l_succ_mess INTO l_v1 SEPARATED BY space.
          *
          CALL METHOD /flm/core=>error
              EXPORTING
                im_type   = /flm/core=>c_mess_success
                im_number = '997'
                im_v1     = l_v1.
      
          IF l_message IS NOT INITIAL.
              l_var = l_message.
              ex_mess_num = '002'.
              ex_msgvar1  = l_var.
              ex_response = 'A'.
              CALL METHOD /flm/core=>error
                EXPORTING
                  im_type   = /flm/core=>c_mess_warning
                  im_number = '002'
                  im_v1     = l_var.
          ELSE.
              ex_value = l_valid.
          ENDIF.
  4. Save

The checkbox will be ticked if the VAT number supplied is valid. 

Adding Web Services to an HTML form

To activate web services for a form the following two updates should be made to the HTML template in the <head> section. They can both be removed if web services are not being used.

Meta data needs to point at the technical web service name as recorded in SOAMANAGER. This is usually the name of the SAP function module with underscores removed and in “Camel” case (each new word capitalised)

<meta id="SAPWebService1" name="ZFlmAclInvokeWs" content=""/>

The web services JavaScript library must be linked in the head section

<script type="text/javascript" src="./Javascripts/soapclient_295SP3_v1.js">//Standard SOAP Client (Web Services)</script>

Two new generic web service functions are delivered as below in the formMethods JavaScript; both are based on the WSCall and WSCallback samples used for existing SAP web services. The next section will show how these can be called.

The request code function invokeWebservicesCheck(arrFormData,checktype) in formMethods is standard and does not need to be changed.

The response code function invokeWebservicesCheck Callback(r,soapResponse) in formMethods is also standard but as new web services are added to support the functionality of the form, additional switch "case" statements will need to be written.

Webservices on HTML forms examples

For HTML forms the WSDL from SOAMANAGER does not need to be extracted as this will be read on demand from SAP. The management of web services is handled via the JavaScript functions described in the previous section and the “soapclient_295SP3_v1.js” file as part of the master structure. If web services are not used this file can be removed from the <head> section but must be included again if required.

The following three use cases explain how to trigger different types of web services and apply the result to update the form.

Note that standard FLM check cycle functionality with HTML templates should be considered if several updates/validations are required.

From FLM SP3 by default the validation, substitution and derivation user exits are not called during a check cycle and a webs service may be a useful replacement.

Updating fields of a form

In the example below we only need to pass two fields from the form into the web service and use a list of the Ids to pass into the call using the getDataArray JavaScript function.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
case "NUM_POS_ID":

        // Call Generic ws # 002 (get position info)

        // Pass in minimum number of fields

        var fieldIds = ["DT_BEGDA", "NUM_POS_ID"];

        var arrFormData = getDataArray(fieldIds);

        invokeWebServiceCheck(arrFormData, "002");

    break;

SAP Control Data and Function logic

An entry in the ZFLM_WS_CNTRL table is required to link index 002 with the specific business function.

MANDT      CCODE FTYPE WSINDEX  PROC_FUNCTION
800 ACL XXXX 0002 ZFM_HR_POSITION_INFO_WS

The interface for this function must match Z_FLM_ACL_INVOKE_WS so it is suggested you copy this function (or the previously created) via SE37.

The position check function can include any custom logic and simply needs to return the name/value pairs with ~ and ; delimiters as for the dropdown example.  An example return would look as below.

TXT_POS_NAME~Solution Architect;TXT_POS_JOB~00010233

Callback

 The result (above array) is passed back to the HTML and the setDataArray  JavaScript code  (see Appendix) performs the reverse of the getDataArray and pushes the value against each name back onto the form field . Note that any retrigger of “onblur” or ”onchange” events must be explicitly handled.

Filling a dropdown

Trigger

In the example below we only need to pass two fields from the form into the web service and use a list of the Ids to pass into the call using the getDataArray JavaScript function.

1:
2:
3:
4:
5:
6:
7:
case "DD_EMPSUBGROUP":
        // Call Generic ws # 001 (rebuild emp subroup)
        // Pass in minimum number of fields
        var fieldIds = ["TXT_MOLGA", "DD_EMPGROUP"];
        var arrFormData = getDataArray(fieldIds);
        invokeWebServiceCheck(arrFormData, "001");
    break;

SAP Control Data and Function logic

An entry in the ZFLM_WS_CNTRL table is required to link index 001 with the specific business function.

MANDTNDT CCODE FTYPE WSINDEX PROC_FUNCTION
800 ACL XXXX 0001 ZFM_HR_DD_EMPSUBGROUP_WS

The interface for this function must match Z_FLM_ACL_INVOKE_WS so it is suggested you copy this function via SE37 when creating the first function.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
DATA :
       lt_data          TYPE /flm/xml_tab_t,
       wa_data          TYPE /flm/xml_tab,
       lt_f4_data       TYPE /flm/sfs_form_data_t,
       wa_f4_data       TYPE /flm/form_data,
       lv_f4_string     TYPE string,
       lv_f4_field      TYPE string.

  CLEAR: lv_f4_string, lt_f4_data, wa_f4_data.

* Normal UE logic to build table of name/value pairs in lt_f4_data
  CALL FUNCTION 'Z_FLM_GET_EMPSUBGROUP_F4'
    EXPORTING
      i_data       = im_form_data
    IMPORTING
      ex_form_data = lt_f4_data.

* Additional code below converts table to array for handling by JS in Callback
* Refresh table for values we want to pass back
  REFRESH lt_data[].

* We need a blank row here
  INSERT wa_f4_data INTO lt_f4_data INDEX 1.

  LOOP AT lt_f4_data INTO wa_f4_data.
    CONCATENATE lv_f4_string ';' wa_f4_data-name '~' wa_f4_data-value INTO lv_f4_string.
  ENDLOOP.

  SHIFT lv_f4_string LEFT DELETING LEADING ';'.

  ex_arr_form_data = lv_f4_string.

In the example above the only business specific code is the call to existing SAP function Z_FLM_GET_EMPSUBGROUP_F4 which by itself would provide a table of name/value pairs and could be called directly in the FLM F4 user exit.

The remaining code takes the name/value pairs to return an array with ~ and ; delimiters.

Callback

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
case "001": //EmpSubgroup rebuild on change of Em group

        var target = $("#DD_EMPSUBGROUP");

        var arrList = arrFormData[1].split(";"); // Split Array

        for (var i = 0; i < arrList.length; i++)

            arrList[i] = arrList[i].split("~");

        flm.loadData(arrList, target, 0, 1); //Populate Dropdown

    break;

The result (above array) is passed back to the HTML in arrFormData[1] and the code above performs the reverse of the SAP function building the table of name/value pairs and loads  the dropdown.

Validating Input

The trigger for validation is identical to the previous examples but requires the use of the return parameters EX_INVALID and EX_MESSAGE within the specific business function.

If an EX_INVALID value other than blank/0 is returned then the Callback process will immediately alert the user with the message contained in EX_MESSAGE and processing will stop.

If you require further validations “on form” once the SAP data has been retrieved via the web service then you will need to leave EX_INVALID as blank/0. As a result you will need to control the alert message and stop further processing within the Callback case and/or formMethods.

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
case "002": //Position Check

        // Push return values onto Form

        setDataArray(arrFormData[1]);

        // Check if we have any issues and put up an alert accordingly

        var errMess = "";

         // Is chief checked

        if ($("#CB_NEWPOS_CHIEF").prop("checked")) {

            errMess = "Two people cannot occupy a chief position, please contact HR for advice.\n";

            }

         if (errMess != "") {

            alert(errMess);

        }

    break;