Skip to Content

Towards the end of the
Dynamic Proxies in ABAP Part 3: Code Generation
we had figured out the XSL transformation for
generating a skeleton implementation of
a dynamic proxy class from its XML description. Without further ado I will now
present the coding for method ZIF_DPX_GUINEA_PIG~WATER as example for an
instance method that raises classical exceptions, discuss its salient features
and subsequently show how it can be generated by extending our XSLT with a few
additional templates:


method ZIF_DPX_GUINEA_PIG~WATER.
data LT_PARAMS type ABAP_PARMBIND_TAB.
data LS_PARAM type ABAP_PARMBIND.
data LT_EXCPTS type ABAP_EXCPBIND_TAB.
data LS_EXCPT type ABAP_EXCPBIND.
data LV_RC type SYSUBRC.

LS_PARAM-NAME = 'IV_LITRES_PROVIDED'.
LS_PARAM-KIND = CL_ABAP_OBJECTDESCR=>EXPORTING.
get reference of IV_LITRES_PROVIDED into LS_PARAM-VALUE.
insert LS_PARAM into table LT_PARAMS.
if RV_LITRES_CONSUMED is requested.
LS_PARAM-NAME = 'RV_LITRES_CONSUMED'.
LS_PARAM-KIND = CL_ABAP_OBJECTDESCR=>RECEIVING.
get reference of RV_LITRES_CONSUMED into LS_PARAM-VALUE.
insert LS_PARAM into table LT_PARAMS.
endif.
LS_EXCPT-NAME = 'DYSENTERY'.
LS_EXCPT-VALUE = 1.
insert LS_EXCPT into table LT_EXCPTS.
MR_HANDLER->INVOKE(
exporting
IR_PROXY = ME
IV_METHOD_NAME = 'ZIF_DPX_GUINEA_PIG~WATER'
IT_EXCEPTIONS = LT_EXCPTS
importing
EV_RC = LV_RC
changing
CT_PARAMETERS = LT_PARAMS ).
case LV_RC.
when 1.
raise DYSENTERY.
when others.
endcase.
endmethod.

As we have noted previously, the above
coding resembles that needed for making a dynamic method call:

    • First, we fill the parameter table LT_PARAMS
      with data references for those parameters in the method’s signature that have
      actually been supplied respectively requested by the caller. The distinction is
      an important one; otherwise this information would get lost and not be at the
      invocation handler’s disposal. Please note that since we are now in the
      caller’s role with respect to the invocation handler, we need to change importing
      into exporting parameters and vice-versa.
    • Similarly, we enumerate the method’s classical
      exceptions into the exception table LT_EXCPTS, using the insertion order
      to determine the associated return code. Of course, this step depends on the
      presence of classical exceptions; it can be omitted if the method in question
      raises class-based exceptions.
    • Now that we have filled the prerequisite
      parameters tables, we call INVOKE on the per-instance invocation handler
      MR_HANDLER. In case we were dealing with a static method, we would need
      to use the static invocation handler ZIF_DP_PROXY~MR_STATIC_HANDLER
      instead.
    • Afterwards we analyze the return code exported
      via parameter EV_RC. If it matches a value previously associated with an
      exception in table LT_EXCPTS, the corresponding exception will be
      raised. Any other return code (particularly zero) is ignored.

All in all, no great surprises here (I
hope). Now we only have to figure out the XSLT templates to produce the code.


The XSLT Abyss


Code Generation (completed)


Encouraged by this success, we can now
tackle the last missing piece, i.e. generating the code for methods RAISE_EVENT
and RAISE_STATIC_EVENT of our interface ZIF_DP_PROXY. As before,
we start with an overview of the code we want to produce. However, to keep
things interesting (and to have an example that exhibits all relevant
features), this time we will concern ourselves with a dynamic proxy class that
implements ZIF_DPX_CLOCK as well as ZIF_DPX_GUINEA_PIG. The
pertinent parts of this ill-conceived chimera’s implementation are listed below:


class LCL_PROXY
definition inheriting from ZCL_DP_PROXY_BASE.

public section.
interfaces ZIF_DP_PROXY.
interfaces ZIF_DPX_CLOCK.
interfaces ZIF_DPX_GUINEA_PIG.
interfaces ZIF_DPX_SIMULATED_OBJECT.

private section.
class-methods RAISE_EVENT_1
importing
INCREMENT type ANY.
methods RAISE_EVENT_2.
methods RAISE_EVENT_3.
endclass.

class LCL_PROXY
implementation.

method ZIF_DP_PROXY~RAISE_EVENT.
data LV_METHOD_NAME type ABAP_METHNAME.

case IV_EVENT_NAME.
when 'ZIF_DPX_CLOCK~TICKED'.
LV_METHOD_NAME = 'RAISE_EVENT_1'.
when 'ZIF_DPX_GUINEA_PIG~HUNGRY'.
LV_METHOD_NAME = 'RAISE_EVENT_2'.
when 'ZIF_DPX_GUINEA_PIG~THIRSTY'.
LV_METHOD_NAME = 'RAISE_EVENT_3'.
when others.
raise exception type ZCX_DP_UNDEF_EVNT_EXCEPTION
exporting
NAME = IV_EVENT_NAME.
endcase.
call method ME->(LV_METHOD_NAME)
parameter-table
CT_PARAMETERS.
endmethod.

method ZIF_DP_PROXY~RAISE_STATIC_EVENT.
data LV_METHOD_NAME type ABAP_METHNAME.

case IV_EVENT_NAME.
when 'ZIF_DPX_CLOCK~TICKED'.
LV_METHOD_NAME = 'RAISE_EVENT_1'.
when others.
raise exception type ZCX_DP_UNDEF_EVNT_EXCEPTION
exporting
NAME = IV_EVENT_NAME.
endcase.
call method (LV_METHOD_NAME)
parameter-table
CT_PARAMETERS.
endmethod.

...

method RAISE_EVENT_1.
raise event ZIF_DPX_CLOCK~TICKED
exporting
INCREMENT = INCREMENT.
endmethod.

method RAISE_EVENT_2.
raise event ZIF_DPX_GUINEA_PIG~HUNGRY.
endmethod.

method RAISE_EVENT_3.
raise event ZIF_DPX_GUINEA_PIG~THIRSTY.
endmethod.

endclass.

The methods we provide for triggering the
proxy’s events expect the associated parameters in the by now familiar
parameter table format suitable for a dynamic method call. We take advantage of
this circumstance and raise the events through dedicated private methods (RAISE_EVENT_*)
with a compatible parameter signature which we call dynamically ourselves, thus
leaving the unenviable task of extracting the event’s parameters from the
appropriate entries in CT_PARAMETERS to the ABAP runtime. Apart from
this trick, the rest of the code is rather unremarkable:

    1. The methods for raising the events need to be
      declared in the proxy class definition’s private section. To name them, a
      consecutive number prefixed with RAISE_EVENT_ is used.
    2. Please note that while both instance and class
      events may be triggered via ZIF_DP_PROXY~RAISE_EVENT, only class events
      are allowed in ZIF_DP_PROXY~RAISE_STATIC_EVENT. In both instances we use
      a case statement to translate the event’s name supplied in IV_EVENT_NAME
      into the name of the appropriate RAISE_EVENT_* method.
    3. In case an invalid event name was supplied, we
      raise exception ZCX_DP_UNDEF_EVNT_EXCEPTION;
      otherwise we invoke the previously determined method through a
      dynamic method call.

Not to squander the rest of your goodwill,
I will not tax your patience again by a piecemeal revelation of the templates
required to generate the above code. Instead, you get the complete XSL
transformation that is used in the current incarnation of the dynamic proxy
framework:


<xsl:transform version=”1.0″
    xmlns:xsl=”http://www.w3.org/1999/XSL/Transform
    xmlns:sap=”http://www.sap.com/sapxsl


  <xsl:output method=”text” omit-xml-declaration=”yes”/>


  <xsl:param name=”PROGNAME”/>
  <xsl:param name=”CLASSNAME”/>
  <xsl:param name=”SYDATE”/>
  <xsl:param name=”SYTIME”/>
  <xsl:param name=”UNAME”/>


  <xsl:strip-space elements=”*”/>


  <xsl:template match=”/”>
      <xsl:apply-templates/>
  </xsl:template>


  <xsl:template match=”ABAP”>
&—-



*& Program  <xsl:value-of select=”normalize-space($PROGNAME)”/>
*& Generated <xsl:value-of select=”$SYDATE”/> at <xsl:value-of select=”$SYTIME”/> by <xsl:value-of select=”$UNAME”/>
&—-



program


To report this post you need to login first.

3 Comments

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

    1. Achim Bangert Post author
      Hello Mick,

      thanks for your enduring interest in my humble blog. As a matter of fact, I do plan to finish this series; however, I’ve changed employers recently and still need to sort some things out first – like getting a laptop capable of running a Mini-SAP system again. So stay tuned!

      Cheers
      Achim

      (0) 

Leave a Reply