Showing posts with label Exceptions. Show all posts
Showing posts with label Exceptions. Show all posts

Friday, August 1, 2014

Handy local exception class

During my exception exploration I came to such conclusion, within local local exception class is sometime handy to have both input parameters, at first message with all its attributes or simple string. Below class fulfill both cases. Below exception class have two optional input parameters, so it's up to programmer what to choose. See below usage examples.

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
    DATAmsgv1 TYPE symsgv READ-ONLY,
          msgv2 TYPE symsgv READ-ONLY,
          msgv3 TYPE symsgv READ-ONLY,
          msgv4 TYPE symsgv READ-ONLY.
    INTERFACES if_t100_message.
    METHODS constructor
      IMPORTING
        iv_text     TYPE clike       OPTIONAL  " simple text input
        is_t100_key TYPE scx_t100key OPTIONAL" message input
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).

    " simple string input
    IF iv_text IS NOT INITIAL.
      cl_message_helper=>set_msg_vars_for_clikeiv_text ).
      if_t100_message~t100key-attr1 sy-msgv1.
      if_t100_message~t100key-attr2 sy-msgv2.
      if_t100_message~t100key-attr3 sy-msgv3.
      if_t100_message~t100key-attr4 sy-msgv4.
    ENDIF.

    " message input
    IF is_t100_key IS NOT INITIAL.
      MOVE-CORRESPONDING is_t100_key TO if_t100_message~t100key.
    ENDIF.

    " special cases
    IF if_t100_message~t100key-msgid IS INITIAL )
      AND  if_t100_message~t100key-msgno IS INITIAL )
      AND  if_t100_message~t100key-attr1 IS NOT INITIAL ).
      if_t100_message~t100key-msgid '00'.
      if_t100_message~t100key-msgno '001'.
    ENDIF.

    " set message attributes
    msgv1 if_t100_message~t100key-attr1.
    msgv2 if_t100_message~t100key-attr2.
    msgv3 if_t100_message~t100key-attr3.
    msgv4 if_t100_message~t100key-attr4.
    if_t100_message~t100key-attr1 'MSGV1'.
    if_t100_message~t100key-attr2 'MSGV2'.
    if_t100_message~t100key-attr3 'MSGV3'.
    if_t100_message~t100key-attr4 'MSGV4'.

  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


START-OF-SELECTION.

  DATAlx_oref TYPE REF TO lcx_msg_exception,
        ls_msg  TYPE scx_t100key.

* example 1 - simple success message
  ls_msg-msgid 'VL'.
  ls_msg-msgno '017'.
  TRY.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'S'.
  ENDTRY.

* example 2 - error message with attributes
  ls_msg-msgid 'VL'.
  ls_msg-msgno '046'.
  ls_msg-attr1 '41000064'" some VBELN
  ls_msg-attr2 'IT007'.    " some sy-uname user

  TRY.
      " ...some coding raising custom exception
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

* example 3 - simple error text message
  DATAlv_text TYPE string.
  TRY.
      " ...some coding raising custom exception
      lv_text 'Some ugly error occcured in program 1! Some stupid error occcured in program 2! Some silly error occcured in program 3!'.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          iv_text lv_text.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

Wednesday, July 2, 2014

Local Exception class & Message


Once I decided to a bit improve my simple custom exception object and equip it with message attributes. I needed local class not global one where you can just click checkbox "With message class". Many functions within SAP works with return attributes like sy-msgv1, sy-msgv2... as e.g. function module 'ENQUEUE_EVVBLKE'. Messages are well designed for this purpose. So why to discover wheel once again.

Note: For final solution roll down till the end :)

I knew exceptions and messages work with interface if_t100_message. I read some articles on net, I looked at James Wood book.  The closest one was on Naimesh Patel site. Btw this site is always helpful.

What I looked for was this, just one filled structure scx_t100key as constructor parameter and nothing else. I did not want to use inside the exception class hardcoded constants with prepared messages key/text.

At first I tried below simple solution

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
     INTERFACES if_t100_message.
    METHODS constructor IMPORTING is_t100_key TYPE scx_t100key.
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).
    if_t100_message~t100key is_t100_key.
  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


The usage:


START-OF-SELECTION.

  DATAlx_oref TYPE REF TO lcx_msg_exception,
        ls_msg TYPE scx_t100key.

* test example 1 - simple success message
  ls_msg-msgid 'VL'.
  ls_msg-msgno '017'.
  TRY.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'S'.
  ENDTRY.

* test example 2 - error message with attributes
  ls_msg-msgid 'VL'.
  ls_msg-msgno '046'.
  ls_msg-attr1 '41000064'" some VBELN
  ls_msg-attr2 'IT007'.    " some sy-uname user

  TRY.
      " ...some coding raising custom exception
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

OK, it's pretty easy, everything looks very well unless you do not try to involve attributes 1-4 of the message. If you do so, it looks strange. Attributes are placed at proper places but surrounded by ampersand characters '&'. Ouu, it does not look very well. Hmm, what to do now?



I debugged the part of SAP code responsible for displaying the message and discovered what's wrong.

There is used below method of the class CL_MESSAGE_HELPER.

SET_MSG_VARS_FOR_IF_T100_MSG (CL_MESSAGE_HELPER)
    CALL METHOD set_single_msg_var
      EXPORTING
        arg    = text->t100key-attr1
        obj    = text
      IMPORTING
        target = sy-msgv1.

The wrong thing is done inside the method  SET_SINGLE_MSG_VAR (CL_MESSAGE_HELPER).



I realized, it looks just for exception attribute inside the class and nothing else. It's pretty clear, that below code would not work any more. There is no attribute named with the vbeln number or username.

Working sample code


Finally I did small modification of my exception class to destroy unwanted ampersands. And voila, it works! Look at the below code.

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
    DATAmsgv1 TYPE symsgv READ-ONLY,
          msgv2 TYPE symsgv READ-ONLY,
          msgv3 TYPE symsgv READ-ONLY,
          msgv4 TYPE symsgv READ-ONLY.
    INTERFACES if_t100_message.
    METHODS constructor IMPORTING is_t100_key TYPE scx_t100key.
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).
    if_t100_message~t100key is_t100_key.
    msgv1 is_t100_key-attr1.
    msgv2 is_t100_key-attr2.
    msgv3 is_t100_key-attr3.
    msgv4 is_t100_key-attr4.
    if_t100_message~t100key-attr1 'MSGV1'.
    if_t100_message~t100key-attr2 'MSGV2'.
    if_t100_message~t100key-attr3 'MSGV3'.
    if_t100_message~t100key-attr4 'MSGV4'.
  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


Now the result looks as follows.