BADi is
an object oriented version of SAP enhancement concept. Its main idea is that
instead of filling special includes with ABAP code in some customer function style='mso-bidi-font-weight:normal'>
EXIT_SAPxxxxxx
style='_nnn
style=',
you are to define some ABAP object class which implements a particular
interface (BADi interface) – a set of predefined method declarations.
What are
the pros of the BADi concept besides the fact it is object-oriented (though I
know some people think OO overweighs all others pros and cons)? At my recent
project I was assigned a role of a development team leader and so I was aware
of software engineering management. And from this point of view BADI is much
better than customer exits. Sometimes more than one developer has different
tasks which include programming of the same customer-exit. One of the possible
consequences is a mixture of the code provoking errors, transport request
locking problems, etc. On the contrary, a particular BADI can have several
independent implementations, and so different tasks can be safely separated
with no source code conflicts or request deadlocks.
And one
more idea... There are still lots of questions on various SAP ABAP forums (including
SDN) concerning ways of searching possible enhancements of one or another
business transaction. BADi
gives you one stable method of searching:
just place a break-point inside the method
CL_EXITHANDLER=>GET_INSTANCE
style=' and then execute the business transaction. After
the program stops at the break-point you can easily obtain BADi name and browse
the source code around the call point to get the most exact knowledge of
“terms and conditions” of the BADi call.
In our
project we had to implement HR functionality, and there were several development
tasks including default value calculations for various infotypes (infotype is a
time dependent chunk of a person attributes – e.g. personal data, address data,
etc., infotype has its unique four-digit code).
In transaction
SMOD you can find a customer enhancement designed for this kind of task - style='mso-bidi-font-weight:normal'>PBAS0001. The enhancement contains
function module EXIT_SAPFP50M_001
,
which is commonly used for setting infotype defaults, and
EXIT_SAPFP50M_002
for additional checks after a user has entered values into infotype fields.
Both user-exits have their counterparts in
BADi HRPAD00INFTY
. These are corresponding
methods IF_EX_HRPAD00INFTY~BEFORE_OUTPUT
and IF_EX_HRPAD00INFTY~AFTER_INPUT
and they are called from nearly the same call-up points of the source code.
It would be
nice to use them, but the matter is that those methods have only importing
parameters and obviously they were not intended to change infotype values.
And after hard
reflections and mental sweating on possible ways of the tasks separation I found
a solution – to create my own BADI and call it from the EXIT_SAPFP50M_001
and EXIT_SAPFP50M_002
.
So, let’s
start with transaction SE18. At the initial screen I entered the name – style='mso-bidi-font-weight:normal'>ZPBAS0001_BADI_FLT and clicked the
button Create
.
By checking
Multiple use
checkbox I allowed my
BADI to have multiple implementations, and that is the main goal of the
proceeding. Now each developer (informed of the BADI existence) can create
his/her own fully independent implementation.
<p class=MsoNormal>But here we
can improve the BADI. As we make developments for HR functionality the
infotype code will always be involved. Different infotypes
have different structure and we cannot make universal code for calculating
default values. What I am leading to is that every implementation of the newly
created BADI will be essentially infotype dependent. In that case I bet the
very first statement of every implementation would be </p>
<div style='mso-element:para-border-div;border:solid windowtext 1.0pt;
mso-border-alt:solid windowtext .5pt;padding:1.0pt 4.0pt 1.0pt 4.0pt;
background:#CCFFFF;margin-left:0cm;margin-right:206.75pt'>
<p class=Sourcecode style='background:#CCFFFF;border:none;mso-border-alt:solid windowtext .5pt;
padding:0cm;mso-padding-alt:1.0pt 4.0pt 1.0pt 4.0pt'><b style='mso-bidi-font-weight:
normal'> ><br>
CHECK</b> > infty = <i style='mso-bidi-font-style:normal'>some_infotype_number</i>.<br
style='mso-special-character:line-break'>
<![if !supportLineBreakNewLine]><br style='mso-special-character:line-break'>
<![endif]></p>
</div>
<p class=MsoNormal>Thus
infotype code is an ideal candidate to become a filter value for
implementations. In the <b style='mso-bidi-font-weight:normal'>Attributes</b>
tab of the BADI definition you can see a checkbox <b style='mso-bidi-font-weight:
normal'>Filter-depend</b>. The checkbox turns on filter capabilities of the
BADI.
<p><img height='400' alt='image' width='533' src='https://weblogs.sdn.sap.com/weblogs/images/3886/Image1_resize.gif' border='0'/>
<p>
<p>
To finalize definition of filter dependent BADI we have to enter some
data element name into <b style='mso-bidi-font-weight:normal'>Filter type</b>
field, and the data element has to accept infotype codes as a value.</p>
<p class=MsoNormal>There are
special requirements for the data element to be used as a <b style='mso-bidi-font-weight:
normal'>Filter type</b>. It has to be associated with some Search help, and one
of the import parameter of the search help must be of the same type as data
element. So, I was not successful when tried hastily to enter INFTY data
element into the <b style='mso-bidi-font-weight:normal'>Filter type</b> field
as it has no associated Search help. I did not find proper SAP standard data
element (maybe I did not search thoroughly) and had to create one of name <b
style='mso-bidi-font-weight:normal'>ZINFTY_FLT</b>. </p>
<p><img height='400' alt='image' width='533' src='https://weblogs.sdn.sap.com/weblogs/images/3886/Image2_resize.gif' border='0'/>
<p>
<p>
<p class=MsoNormal>Also I have
created a Search help <b style='mso-bidi-font-weight:normal'>ZH_T582A_BADI</b> with
export parameter of type <b style='mso-bidi-font-weight:normal'>ZINFTY_FLT</b>.
</p>
<p><img height='400' alt='image' width='533' src='https://weblogs.sdn.sap.com/weblogs/images/3886/Image4_resize.gif' border='0'/>
<p>
<p>
<p class=MsoNormal>Finally, I
associated previously created Search help with new Data element. </p>
<p><img height='400' alt='image' width='533' src='https://weblogs.sdn.sap.com/weblogs/images/3886/Image3_resize.gif' border='0'/>
<p>
<p>
<p class=MsoNormal>After that
I could successfully enter the name of my Data element as the Filter type of
the BADI.</p>
<p class=MsoNormal>To be
honest, the requirement looks odd. At least, I do not clearly understand the
reason for an idea of obligatory Search help connection. Certainly defining
filter values with Search help is convenient but what’s wrong if one can enter
values manually?</p>
<p class=MsoNormal>Why use
Filtering? One can think that all the mess is about getting rid of one <b
style='mso-bidi-font-weight:normal'>CHECK</b> statement. But do not forget that
without filtering every time the BADI fires it creates class instances for all
implementations defined and that costs.</p>
Now it’s
time to define methods of the BADI interface. It is done in the style='mso-bidi-font-weight:normal'>Interface tab of BADI definition. Here
I can enter method names. Being not much eccentric I called them style='mso-bidi-font-weight:normal'>GET_DEFAULT_VALUES and style='mso-bidi-font-weight:normal'>CHECK_BEFORE_UPDATE.
By double
clicking at the method name we are driven into a common class/interface
designer (SE24). And here we define all the method parameters. Note that each method
has one predefined import parameter
FLT_VAL of type ZINFTY_FLT for we defined the
BADI as filter dependent.
Now the
definition of the BADI seems to be completed and we can click the button style='mso-bidi-font-weight:normal'>Save. As a result the BADI interface
will be activated and a special proxy class will be generated and also
activated.
The BADI
now is almost ready for an implementation. The final stroke is to call it up
somewhere. At the beginning of EXIT_SAPFP50M_001
function module we insert a special aided fragment of code. First, by
calling method style='mso-bidi-font-weight:normal'>CL_EXITHANDLER=>GET_INSTANCE
style='
we obtain an instance of the proxy
class, implementing BADI interface, and examine whether or not any
implementation exists.
If it does,
then we call appropriate method of the interface instance which does the rest.
Note that before the call we calculate
proper filter value, and in this case it is an infotype code. At the first
glance it seems slightly odd that we place a single call to the BADI method while
it was defined as Multiple use
. No
internal tables, no loop. Actually the interface instance is the instance of
the proxy class which was generated after saving BADI definition. Each proxy
class method contains a standard code snippet which finds and calls all the
implementations complying with filter value.
Global data
declarations:
>CLASS
> cl_exithandler style='mso-bidi-font-weight:normal'>DEFINITION LOAD
.
DATA
:
act_imp_existing TYPE
sxrt_boolean,
pbas0001_badi_instance style='mso-bidi-font-weight:normal'>TYPE REF
TO
zif_ex_pbas0001_badi.
CONSTANTS:
c_exit_name TYPE
exit_def VALUE
'ZPBAS0001_BADI'.
BADi call:
*&----
*
*& Include
ZXPADU01
*
*&----
*
*"----
-
""Lokale Schnittstelle:
*" IMPORTING
*" VALUE(TCLAS) LIKE
PSPAR-TCLAS
*" VALUE(INNNN) LIKE
PRELP STRUCTURE
PRELP
*" VALUE(IPSYST) LIKE
PSYST STRUCTURE
PSYST
*" VALUE(I001P) LIKE
T001P STRUCTURE
T001P
*" VALUE(I503) LIKE
T503 STRUCTURE
T503
*" EXPORTING
*" VALUE(INNNN) LIKE
PRELP STRUCTURE
PRELP
*" CHANGING
*" REFERENCE(IPREF) LIKE
PREF STRUCTURE
PREF
*"----
-
IF
pbas0001_badi_instance style='mso-bidi-font-weight:normal'>IS INITIAL
.
CALL
METHOD
cl_exithandler=>
get_instance
EXPORTING
exit_name
= c_exit_name
IMPORTING
act_imp_existing
= act_imp_existing
CHANGING
instance
= pbas0001_badi_instance
EXCEPTIONS
no_reference
= 1
no_interface_reference
= 2
no_exit_interface
= 3
class_not_implement_interface
= 4
single_exit_multiply_active
= 5
cast_error
= 6
exit_not_existing
= 7
data_incons_in_exit_managem
= 8
OTHERS
= 9.
IF
sy-subrc <> 0.
MESSAGE
ID
sy-msgid
TYPE
sy-msgty
NUMBER
sy-msgno
WITH
sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF
.
ENDIF
.
IF
NOT
act_imp_existing IS
INITIAL
.
CALL
METHOD
pbas0001_badi_instance->
get_default_values
EXPORTING
tclas
= tclas
ipsyst
= ipsyst
i001p
= i001p
i503
= i503
flt_val =
innnn-infty
CHANGING
innnn
= innnn
ipref
= ipref.
ENDIF
.
To create a
BADI implementation we start SE19 transaction. After entering implementation
name and BADI definition name you also can manually enter the name of the class
already existent which will implement the BADI, or the system can generate it
automatically.
Strange
enough, for some reason or another a single class cannot be used for
implementing more than one BADI, in spite the fact that a class can implement
arbitrary number of interfaces. There could be circumstances when it is convenient
to use a single class to implement more than one BADI. Let’s treat it as an
item to a wish list for coming versions of ABAP.
I intend
this particular implementation to create some custom infotype automatically
when user executes some personnel management action (infotype 0000) or changes
somehow organizational assignment (infotype 0001). At the Defined filters
ALV control I insert two items: 0000 and 0001.
Finally,
after entering appropriate code into a method implementation we can activate
implementation and begin testing and debugging.