Generic
Synchronization | What is
a data container?
Wrapper Functions for Generic Synchronization
Generic synchronization allows mobile applications to call any SAP function
module residing in any SAP backend. To allow for generically calling any module,
Generic Sync needs to make assumptions on the function module's interface. Therefore
any callable modules needs to conform to a standard interface defined by MI.
This means that the actual function module (representing the server-side business
logic of your application) needs to be wrapped in a so-called 'wrapper function'
that implements this standard interface. This document explains the interface
and development of wrapper functions in detail.
You should be familiar with the data
container concept before reading this chapter and should be able to read
ABAP coding.
- We will first describe the call cycle of a wrapper
function in much detail
- We will then generate a wrapper function using
transaction ME_WIZARD
- We then examine the wrapper function coding coding.
- We finish the document with some annotations
about important issues when developing wrapper functions.
Wrapper function call cycle
The complete cycle for data container processing on the MI server and the role
of the wrapper function therein is shown below:
- Data containers coming from the mobile device into the MI ABAP Server Component
are processed synchronously or asynchronously, depending on their processing
type defined by the mobile application at data container creation. Asynchronous
processing is started by a scheduled batch job (
WAF_MW_MAPPING
)
that reads the inbound queue, that is the queue of all containers awaiting
to be processed. For synchronously processed data containers, the processes
starts with step no. 2
- The module name given in the data container's header is mapped to the actual
name of the wrapper function by reading table
BWAFMAPP
. The idea
of this mapping is that the actual name of the wrapper function does not need
to be hard-coded into the application's Java code for container creation.
Instead, the mobile application uses an alias name for the module which is
mapped to the correct name by the MI server. Whenever the wrapper function
name was to change, it would be sufficient to change the corresponding BWAFMAPP
entry and not change any Java code.
- The RFC destination, in which the wrapper function resides is determined
by reading table
MEMAPPDEST
on the MI server. If no RFC destination
is found, the wrapper function is expected to reside in the current system.
- The wrapper function is called in the corresponding RFC destination. At
this point, the application is taking over control of the process.
- The wrapper function first performs a so-called 'inbound mapping', that
means it maps the generic data container structure to the specific interface
of the wrapped function module. This is basically performed by looping through
the data container's body table and mapping the selected keys and values to
the new structures.
- When a data containers is processed asynchronously, the wrapper function
is called by a scheduled batch job (report WAF_MW_MAPPING). The R/3
user under which the call is processed is hence the batch job user and not
the device user. The authority check in the wrapped function module will hence
be done for the batch user (and not for the device user), because the system
variable SY-UNAMEdoes not contain the expected user at runtime of
the module!. To prohibit unauthorized processing, a simulated authority check
should be carried (via function module SUSR_AUTHORITY_CHECK_SIMULATE).
- The wrapped function module is called. At this stage, the actual business
process is triggered and, for example, the data collected on the mobile device
are updated in the application's database.
- The return parameters of the wrapped function module need to be 'outbound
mapped' to the data container structure. This is basically a reversal of step
5)
- The wrapper function passes its outbound containers back as the RFC response
of the call in step 4)
- The MI server add the received data containers to the outbound queue. If
the data container was processed asynchronously, it will be transported back
to the device on the device's next synchronization. If the data container
was processed synchronously, the outbound data container will be transported
back to the device straight-away.
Generating wrapper functions
To ease development of wrapper functions, SAP offers the transaction ME_WIZARD.
Starting with a function module that you want to wrap, an alias name that you
want to use for it in your mobile application and a function group which holds
the generated coding, the transaction automatically generates the wrapper function.
The MI Wizard is always started in the SAME system in which the function module,
that is to be wrapped, resides. The MI Wizard exists in any system that has
a mySAP Technology (aka: SAP_BASIS) >= 6.10. For systems with mySAP Technology
4.5 - 4.6C, the R/3 Plug-In needs to be applied to have the transaction ME_WIZARD
available.
 |
- In Unicode-enabled systems, the generated coding may need to be modified.
- The Java skeletons that can be generated using the ME_WIZARD are out-of-date
and do not conform with the Generic Sync AP.
|
Using the MI Wizard
Usage of the MI Wizard is very straightforward:
- Launch SAPGui and log on to the SAP system in which the function module,
that you want to call via Generic Sync, resides.
- Enter /nme_wizard into the transaction field to start the MI Wizard.
- Enter the Java alias for the function module into the field Method name.
The Java alias is the alias name under which the function module is known
on the mobile device. The alias name is used when creating data containers
that shall later be processed by the wrapper function module.
- Enter the name of the function module that you want to wrap into the field
Function module.
- Enter the name of the function group that will hold the generated coding
into the field Function Group.
You may need to first create the function group via the ABAP/4 Workbench (transaction
SE80). In order to allow transportation of the generated coding, the function
group should lie in a transportable package. For more information on function
groups, packages and transportation, please consult the online documentation
for the ABAP/4 Workbench.
- Optional: enter a name for the generated function module.
By default, the name of the generated function module would be ME_<function
module>, where <function module> is the name of the function module
entered in step 4.
- Click Generate FM holder to generate the wrapper function module and an
entry in the mapping table BWAFMAPP. BWAFMAPP holds the mapping between the
Java alias (step 3) and the name of the generated function module.
If in your system settings the change recording is activated, you'll be prompted
to furnish a transport request in for the generated function module and the
table entry. If you already created a transport request for these development
objects in the Transport Organizer (transaction SE09), use that request. Otherwise
you can create a transport request in the dialog box.
- The wrapper function module is now generated and can be examined in transaction
SE37. Just copy the name of the generated module, start transaction SE37,
paste the name of the function module and select Show (F7).
- Do not continue to generate Java skeletons, as the generated Java skeletons
do not conform to the new Generic Sync API shipped with MI 2.1 SP1!!!
Wrapper function coding examined
We now examine the generated coding of the wrapper functions. In the ensuing
example, we look at the wrapper function MDK_SUSR_USER_ADRRESS_READ
that is also used in the tutorial on generic sync. It wraps the function module
SUSR_USER_ADDRESS_READ
which reads user and address information
for a given user.
In the description, we'll use the same numbering as in the illustration
shown above.
- Data containers are read from the inbound queue, that means the tables
MESYHEAD
and MESYBODY
.
- The mapping information is read from BWAFMAPP that only has the two fields
METHOD
and FUNCTION
. METHOD
is the
alias name of the function module as it is furnished by the application at
data container creation. FUNCTION
is the name of the wrapper
function.
- The RFC destination in which the wrapper function resides is read from table
MEMAPPDEST. It has the following fields: METHOD (same alias name for the wrapper
function as in 2)), RFCDEST (technical name of an RFC destination as maintained
in transaction SM59; for example PRDCLNT800 for client 800 in system PRD)
- After determining mapping and RFC information, the MI Server calls the wrapper
function in the following way:
call function function
destination rfcdest
importing
status = status
tables
inbound_container = inbound_container
outbound_container = outbound_container
exceptions
communication_failure = 1
system_failure = 2
others = 3.
function
is name of the wrapper function as determined in
step 2). rfcdest
is the name of the RFC destination as determined
in step 3). If no RFC destination could be determined (because the function
function
is residing in the same system, the call is done locally).
status
is the error status set by the application. inbound_container
is the data container's body that was read in step 1). outbound_container
is the exporting information of the wrapper function, that means the response
data container that the application will send back to the device. The outbound
container will be filled during the outbound mapping in step 7)
In our example, the called wrapper function is MDK_SUSR_USER_ADDRESS_READ
that implements this standard interface:
FUNCTION MDK_SUSR_USER_ADDRESS_READ.
*"--------------------------------------------------------------------
*"*"Local interface:
*" EXPORTING
*" VALUE(STATUS) LIKE BWAFSYHEAD-STATUS
*" TABLES
*" INBOUND_CONTAINER STRUCTURE BWAFCONT
*" OUTBOUND_CONTAINER STRUCTURE BWAFCONT
*"--------------------------------------------------------------------
- The wrapper function first performs
the so-called inbound mapping. Therefore loops through the data container
body's table and maps the data container name-value-pair structure to the
corresponding interface parameters of the called function module (see 6).
For structured parameters, the mapping is as follows:
* Declare variable user_name of same type as function module parameter
* and fill it from data container body
DATA user_name LIKE usr01-bname .
LOOP AT inbound_container WHERE fieldname = 'USER_NAME'.
user_name = inbound_container-fieldvalue.
ENDLOOP.
For table parameters, the data containers structure carries the parameter
LINENUMBER
to differentiate the different lines of a table. The
mapping then looks like this:
* Declare variable user_name_tab of same type as function module parameter
* and fill it from data container body.
DATA user_name_tab like ususers occurs 0 with header line.
LOOP AT inbound_container WHERE fieldname = 'USER_NAME_TAB' .
user_name_tab = inbound_container-fieldvalue.
APPEND user_name_tab .
ENDLOOP.
- To prohibit unauthorized processing, a simulated authority check
should be carried out via the function module SUSR_AUTHORITY_CHECK_SIMULATE.
You should use the following coding template for the authority check simulation:
DATA: syncuser LIKE usr02-bname,
lv_unauthorized LIKE sy-subrc.
READ TABLE inbound_container WITH KEY fieldname = 'SYNCUSER' .
IF sy-subrc = 0.
syncuser = inbound_container-fieldvalue.
CALL FUNCTION 'SUSR_AUTHORITY_CHECK_SIMULATE'
EXPORTING
USER_NAME = syncuser
OBJECT = <to be filled>
FIELD1 = <to be filled>
VAL1 = ret
FIELD2 = <to be filled>
VAL2 = <to be filled>
... = .... (possibly more fields to be checked)
IMPORTING
SY_SUBRC = lv_unauthorized
EXCEPTIONS
NOT_AUTHORIZED = 1
USER_NOT_EXISTS = 2
INTERNAL_ERROR = 3
OTHERS = 4.
IF SY-SUBRC <> 0 or lv_unauthorized<> 0.
lv_unauthorized = 4.
ENDIF.
ELSE.
lv_unauthorized = 4.
ENDIF.
** You now need to handle the error, for example by sending an error message back
** to the PDA.
IF lv_unauthorized = 4.
outbound_container-fieldname = 'ERROR' .
outbound_container-linenumber = 0.
outbound_container-fieldvalue = 'not authorised' .
APPEND outbound_container.
RETURN.
ENDIF.
- At this stage, the wrapped function should be called. In our
example this would be the function module SUSR_USER_ADDRESS_READ:
* call function module with business logic
call function 'SUSR_USER_ADDRESS_READ'
EXPORTING
USER_NAME = USER_NAME
READ_DB_DIRECTLY = READ_DB_DIRECTLY
IMPORTING
USER_ADDRESS = USER_ADDRESS
USER_USR03 = USER_USR03
EXCEPTIONS
others = 1.
It is also possible to call additional function modules.
- In the outbound processing of the wrapper function module, the
data returned by the wrapped function module(s) is packaged in outbound containers
that are then returned back to the device. The outbound mapping is the inverse
process of the inbound mapping discussed in 5).
This would be the right moment to limit data load on the device by only returning
the necessary information to the device and not necessarily all EXPORTING,
CHANGING and TABLES parameters of the wrapped function modules!
If you want to notify the device user about application errors, the errors
need to be mapped to outbound containers also.
For structured parameters, the coding for outbound mapping would look like
this.:
* Map parameters of wrapped function module to data container structure
outbound_container-fieldname = 'USER_ADDRESS' .
outbound_container-linenumber = 0 .
outbound_container-fieldvalue = USER_ADDRESS .
APPEND outbound_container.
For TABLES parameters, the outbound mapping would take this form:
* Map parameters of wrapped function module to data container structure
* Use field LINENUMBER to differentiate lines of a table
counter = 0.
LOOP AT user_name_tab.
outbound_container-fieldname = 'USER_NAME_TAB' .
outbound_container-linenumber = counter.
outbound_container-fieldvalue = USER_NAME_TAB .
APPEND outbound_container.
counter = counter + 1.
ENDLOOP.
In case of application errors, you may want to transport the error information
back to the device user:
* Error handling, if wrapped function module throws an exception
IF sy-subrc <> 0
outbound_container-fieldname = 'ERROR' .
outbound_container-linenumber = 0.
outbound_container-fieldvalue = 'An application error occured'.
APPEND outbound_container.
ENDIF.
- The data containers created by the wrapper function are transported
back to the MI server.
- The outbound containers are added to the outbound queue, for example, to the tables
MESYHEAD and MESYBODY. The user will receive them on next
sync.
Wrapper function development
During development of wrapper functions, the following issues should be kept
in mind:
- Only systems of mySAP Technology (that is: SAP_BASIS/SAP_ABA) release 4.5
or above can be called, because the data element BWAFCONT only exists for
these releases. For releases 4.5 - 4.6C, the R/3 Plug-In needs to be applied
to the system (PI 2001.1 or later).
- As wrapper functions typically are processed asynchronously by a batch user,
the authority check of the wrapped function module will not fulfill its purpose.
You should ALWAYS simulate the authority check for the user who created the
data container. The user information can be taken from the data container.
- Wrapper functions can be called in any RFC connection maintained in table
MEMAPPDEST. To call non-SAP systems, just use an RFC connection pointing to
an SAP Business Connector and create an method on the SAP Business Connector
that has the same interface as a wrapper function module.
- The generated coding may sometimes not be unicode-enabled. You'll need to
modify the generated coding then.
- In order to minimize the data transport to the device, you can modify the
generated coding in such a way that only relevant data is actually put into
outbound containers. The same optimization could also be done by modifying
or wrapping the wrapped function module directly.
- The Java skeletons generated by the MI Wizard can no longer be used. They
do not conform to the Generic Sync API.
- The MI Wizard also generates entries for the table BWAFMAPP. These are integral
part of your development and need to be transported.
- Wrapper functions will be called by the MI framework. They do not need to
be RFC-enabled.