jueves, 16 de enero de 2014

Ejemplo de SHARED MEMORY OBJECTS

 Voy a iniciar 2014 activando este blog con una serie de artículos sobre SAP, orientados a la parte técnica, aunque alguno será enfocado a presentar algún producto interesante de SAP o hablar de algún nicho de mercado donde SAP está trabajando activamente.

En primer lugar, hablaré de los objetos en memoria compartida (SHARED MEMORY OBJECTS).


Esta memoria va más allá de la clásica memoria SET/GET, EXPORT/IMPORT donde se pueden exportar a lo sumo tablas, pero no instancias de objetos ABAP, lo cual es una ventaja y conviene saber usarlo si en algún cliente es necesario compartir entre programas información de objetos. Esto simplifica el código porque de otro modo, hay que leer los atributos del objeto, exportarlo a memoria con las sentencias clásicas, importarlo en otro lugar y usar esa información y a veces enviarla de vuelta modificada, lo cual ya sólo escribirlo cansa, a parte de la dificultad de trabajar con IDs de memoria los cuales pueden causar problemas al perderles la pista a medida que el proyecto avanza.

De otro modo si el objeto se lleva a memoria compartida y es posible leerlo y escribir sobre él, es mucho más sencillo este tratamiento, sólo es necesario saber tratarlo y conocer las limitaciones que pueda tener esta operativa.

Otra ventaja que tienen los SHARED MEMORY OBJECTS es el tiempo de ejecución. A veces  la única forma de transmitir información de SAP de una transacción a otra es grabar los datos en la base de datos. Esto implica que es necesaria la actividad del usuario para que esta transmisión sea posible,  lo cual complica el procedimiento. Si hay un despiste, se pierde información y eso debería evitarse en lo posible.



Elaboramos un ejemplo sencillo donde dos programas necesiten compartir y actualizar un objeto en memoria.

Por ejemplo, una pantalla de selección con una variable CHAR de longitud 2, el programa mostrará lo que metamos en esa variable. Al mismo tiempo esta variable actualiza un objeto con un atributo que también sea CHAR de longitud 2.

Este objeto lo vamos a compartir a través del metodología de SHARED MEMORY OBJECTS.
A su vez hacemos otro programa que lea la memoria compartida y escriba el atributo del objeto compartido en pantalla.

Lo iremos modificando y mostrando varias veces para demostrar que efectivamente podemos crear un flujo de datos a través de los dos programas unidos a través de la memoria compartida.
En primer lugar creamos una clase que va a contener los objetos a compartir y que se denominará ROOT. Tendrá dos características a  tener en cuenta.:

1) Su interfaz será  IF_SHM_BUILD_INSTANCE.
Esto le asigna por defecto un  método constructor llamado build
2) El pincho Shared Memory-Enabled debe estar marcado.
3) Esta clase tendrá los métodos que  leerán y modificaran datos.


En el ejemplo se implementan dos métodos, con variable de entrada y salida tipo char de longitud 2, llamadas im_value y ex_value.
El método READ_DATA

method READ_DATA.
 ex_value = value.
endmethod.

 Y el método SET_DATA

METHOD set_data.

  IF im_value IS INITIAL AND value IS INITIAL.
    value = '01'.
  ELSE.
    value = im_value.
  ENDIF.

ENDMETHOD.

También implementamos el método build


method IF_SHM_BUILD_INSTANCE~BUILD.
  
data: lcl_test1 type ref to ZCL_SMO_TEST1,
        lcl_shma_test1 type ref to ZSHMA_AREA_TEST1,
        lx_exception type ref to cx_root.
  try.
      lcl_shma_test1 = ZSHMA_AREA_TEST1=>attach_for_write( ).
    catch cx_shm_error into lx_exception.
      RAISE EXCEPTION type cx_shm_build_failed
        EXPORTING
          previous = lx_exception.
  endtry.

  try.
      CREATE OBJECT lcl_test1 area handle lcl_shma_test1.
      lcl_shma_test1->set_root( lcl_test1 ).
      lcl_test1->set_data( ).
      lcl_shma_test1->detach_commit( ).
    catch cx_shm_error into lx_exception.
      RAISE EXCEPTION type cx_shm_build_failed
        EXPORTING
          previous = lx_exception.
  endtry.

  if invocation_mode = cl_shm_area=>invocation_mode_auto_build.
    CALL FUNCTION 'DB_COMMIT'.
  endif.
endmethod.


A través de la transacción SHMA creamos un área de memoria.
La clase raíz y la clase constructor será la clase root. En la pestaña “historial” se podrá ver quien creó y modificó el área.



Ya creado esto sólo nos queda escribir código en el programa que enviará datos a memoria y escribir código en el programa que leerá el objeto compartido.

En  la ayuda de SAP podemos leer lo siguiente.
Para el programa que escribe la información:

DATA: my_handle TYPE REF TO cl_my_area, 
      my_data   TYPE REF TO cl_my_data. 

TRY. 
    my_handle = cl_my_area=>attach_for_write( ). 

    CREATE OBJECT my_data AREA HANDLE my_handle. 

    my_handle->set_root( my_data ). 

    my_data->read_spfli( ). 

    my_handle->detach_commit( ). 
-   CATCH cx_shm_attach_error. 
    ... 
ENDTRY.
 Y para el programa que lee la información: 
DATA my_handle TYPE REF TO cl_my_area. 

TRY. 
    my_handle = cl_my_area=>attach_for_read( ). 

    my_handle->root->output_spfli( ). 

    my_handle->detach( ). 

  CATCH cx_shm_attach_error. 
    ... 
ENDTRY.

Teniendo en cuenta que la clase root en nuestro ejemplo se llama:

ZCL_SMO_TEST1 y la clase asociada al área compartida, ZSHMA_AREA_TEST1.

Creamos un report 1, en el cual introducimos una variable y la exportamos al atributo “value” del objeto compartido y mostramos por pantalla el valor de la variable introducida. El código es sencillo y es el siguiente.

REPORT  zsmreport1.

PARAMETERS: p_value TYPE c LENGTH 2.

* Define the area and memory object references
DATA: lcl_data TYPE REF TO zcl_smo_test1,
      lcl_area TYPE REF TO zshma_area_test1,
      lv_exception TYPE REF TO cx_root.

TRY.
    lcl_area = zshma_area_test1=>attach_for_write( ).
    CREATE OBJECT lcl_data AREA HANDLE lcl_area.
    CALL METHOD lcl_area->set_root
      EXPORTING
        root = lcl_data.

    CALL METHOD lcl_area->root->set_data(
      EXPORTING
        im_value = p_value ).

    lcl_area->detach_commit( ).

  CATCH cx_shm_attach_error.
ENDTRY.

WRITE: 'El valor de entrada es ',  p_value.

Creamos un report 2 en el cual leemos el atributo del objeto compartido y lo mostramos por pantalla. El código es el siguiente.

REPORT  zsmreport2.


DATA: gv_value TYPE c LENGTH 2.
* Define the area and memory object references
DATA: lcl_area TYPE REF TO zshma_area_test1.

TRY.
     lcl_area = zshma_area_test1=>attach_for_read( ).

     call method lcl_area->root->read_data
       IMPORTING ex_value =  gv_value.

    lcl_area->detach( ).

  CATCH cx_shm_attach_error.

ENDTRY.

WRITE: 'El valor en memoria es ',  gv_value.

Probando los programas se ve que efectivamente se comparte una variable a través del atributo de la clase ROOT.

Este es un ejemplo sencillo aunque los SHARED MEMORY OBJECTS, muestran toda su potencia cuando compartimos objetos entre programas, caso que puede darse fácilmente en un cliente real.
Una última cosa es cómo visualizar el valor del objeto compartido. Vamos a la transacción SHMA.

 Pulsamos en el icóno “Monitor”



Y pulsamos en el área que nos interese con doble click.



 Seleccionamos la instancia que queramos conocer, pulsamos el icono leer versión activa
 y se mostrará en un modo nuevo los datos a visualizar.



Pulsamos:





 Así podemos comprobar los valores que se comparten sin necesidad de debugging.



Más ayuda en :

http://help.sap.com/saphelp_nw70/helpdata/en/c5/85634e53d422409f0975aa9a551297/frameset.htm