4D v16

Servicios basados en los procedimientos almacenados (ejemplo)

Inicio

 
4D v16
Servicios basados en los procedimientos almacenados (ejemplo)

Servicios basados en los procedimientos almacenados (ejemplo)  


 

 

En el ejemplo de la sección Importación con procedimientos almacenados (ejemplo), un procedimiento almacenado se inicia y termina cada vez que se solicita una operación de importación de datos. En este ejemplo, un procedimiento almacenado se lanza automáticamente cuando se inicia la base del servidor y puede iniciarse y detenerse a voluntad por cualquier 4D conectado a la base. Tan pronto como se ejecuta, el procedimiento almacenado puede responder de manera asincrónica a múltiples peticiones enviadas por los clientes conectados a la base.

Mientras que la sección Importación con procedimientos almacenados (ejemplo), muestra cómo optimizar un servicio 4D Server existente, este ejemplo muestra cómo implementar servicios novedosos y personalizados disponibles para todos los equipos 4D client conectados. Además, este ejemplo puede utilizarse como modelo para la creación de sus propios servicios.

El procedimiento almacenado es lanzado automaticamente por el Método base On Server Startup:

 
  ` Método de base On Server Startup
 START SP SERVICES

Como el Método base On Server Startup lanza al método de proyecto SP SERVICES como un procedimiento almacenado, SP SERVICES comienza a correr tan pronto como la base se abre con 4D Server, bien sea que haya o no clientes conectados a la base. En la siguiente imagen, la ventana de administración de 4D Server muestra el procedimiento almacenado en ejecución cuando ningún cliente está conectado.

Este es el método de proyecto START SP SERVICES:

  ` START SP SERVICES Project Method
 ◊vlSPServices:=Execute on server("SP SERVICES";32*1024;"SP SERVICES";*)

Como el comando Execute on server actúa como New process al llamarse en la máquina servidor, el mismo método (START SP SERVICES) puede utilizarse en el equipo servidor o en una máquina cliente para iniciar a voluntad el método SP SERVICES como un procedimiento almacenado en el equipo servidor.

El método de proyecto STOP SP SERVICES “ordena” detenerse al método de proyecto SP SERVICES.

  ` Método de proyecto STOP SP SERVICES
 SET PROCESS VARIABLE(◊vlSPServices;vbStopSPServices;True)

Cuando se inicia el método de proyecto SP SERVICES, da a la variable proceso vbStopSPServices el valor False y luego ejecuta un bucle hasta que esta variable Booleana se convierte en True. El comando , permite a todo proceso usuario ejecutado en el servidor o en un equipo cliente modificar el valor de la variable vbStopSPServices, y por lo tanto detener el procedimiento almacenado a voluntad.

El procedimiento almacenado debe poder recibir peticiones de clientes y responder de manera asincrónica en cualquier momento y sin importar el orden. Una manera directa de asegurar esta comunicación es utilizar una tabla.

La tabla [SP Requests] contiene los siguientes campos:

  • [SP Requests]reqID es asignado utilizando el comando Sequence number. Este campo identifica cada petición de manera única.
  • [SP Requests]reqType describe el tipo de la petición.
  • [SP Requests]reqStatus puede tomar uno de los siguientes valores:

ValorDescripción
1se publicó la petición pero no se ha procesado.
0se ha procesado con éxito la petición.
< 0se procesó la petición pero ocurrió un error.

Nota: estos valores se eligen arbitrariamente para este ejemplo, no son impuestos por 4D.

  • [SP Requests]reqData es un BLOB que contiene los datos de la petición. Puede contener los datos enviados por el solicitante o los datos devueltos por el procedimiento almacenado al solicitante.
  • [SP Requests]reqParams contiene eventualmente los valores de los parámetros enviados por el solicitante al procedimiento almacenado.

La comunicación entre un proceso cliente y un procedimiento almacenado puede implementarse utilizando los comandos GET PROCESS VARIABLE, SET PROCESS VARIABLE y VARIABLE TO VARIABLE. Por ejemplo, esta solución utilizada en la sección Importación con procedimientos almacenados (ejemplo), como también en el método de proyecto STOP SP SERVICES listado anteriormente.

Acá, el sistema debe permitir al procedimiento almacenado recibir y reenviar las cantidades variables de datos. Puede utilizar arrays, incluyendo arrays de texto e imagen), pero hay dos razones principales para preferir el empleo de una tabla:

  • El algoritmo de gestión de peticiones vía los registros es más fácil de implementar. Enviar una petición desde un equipo cliente consiste simplemente en añadir una petición en la tabla. Responder a la petición desde el procedimiento almacenado consiste simplemente en modificar esta petición.
  • Como las peticiones se almacenan en una tabla, se guardan en el disco. Por lo tanto, si el tamaño de una petición es importante, no será un problema en la medida en que puede suprimirse de la memoria (a diferencia de los datos almacenados en los arrays).

El método de proyecto Client post request es un método genérico para enviar una petición:

  ` Método de proyecto Client post request
  ` Client post request ( Cadena { ; Texto } ) -> Entero largo
  ` Client post request ( Tipo de petición { ; Parámetros } ) -> Número de petición
 CREATE RECORD([SP Requests])
 [SP Requests]reqID:=Sequence number([SP Requests])
 [SP Requests]reqType:=$1
 [SP Requests]reqStatus:=1
 If(Count parameters>=2)
    [SP Requests]reqParams:=$2
 End if
 SAVE RECORD([SP Requests])
 $0:=[SP Requests]reqID

El método devuelve el número de la petición, cuya unicidad está garantizada por el uso del comando Sequence number. Una vez añadido el registro a la tabla [SP Requests], el cliente no tiene que interrogar regularmente el campo [SP Requets]redStatus hasta que el procedimiento almacenado termine de procesar la petición.

El método de proyecto Client get result es un método genérico para probar el estado de la petición. Como se explicó anteriormente, tan pronto como el campo [SP Requets]redStatus se vuelve diferente de 1, el cliente sabe que el procedimiento almacenado ha tratado (con éxito o no) la petición.

  ` Método de proyecto Client get result
  ` Client get result ( Entero largo ; ->BLOB {; Entero largo } ) -> Entero largo
  ` Client get result ( Número de petición ; ->Datos {; Duración } ) -> Código del error
 C_LONGINT($0;$1;$vlDelay)
 $0:=1
 $vlDelay:=0
 If(Count parameters>=3)
    $vlDelay:=$3
 End if
 READ ONLY([SP Requests])
 Repeat
    QUERY([SP Requests];[SP Requests]reqID=$1)
    If(Records in selection([SP Requests])>0)
       If([SP Requests]reqStatus&NBSP;#&NBSP;1)
          $2->:=[SP Requests]reqData
          READ WRITE([SP Requests])
          While(Locked([SP Requests]))
             WAITING LOOP($vlDelay)
             LOAD RECORD([SP Requests])
          End while
          DELETE RECORD([SP Requests])
          $0:=[SP Requests]reqStatus
       End if
    Else
  ` Se perdió el registro de la petición
  ` Esto no debería suceder. Pero de todas formas establece el código de error -2 (valor arbitrario)
       $0:=-2
    End if
  ` La petición aún no ha sido procesada
    If($0=1)
       WAITING LOOP($vlDelay)
    End if
 Until($0&NBSP;#&NBSP;1)
 READ ONLY([SP Requests])

Si la petición fue administrada con éxito por el procedimiento almacenado, el método copia el resultado (si lo hay) del registro al BLOB cuyo puntero se pasó como parámetro. El método llamante luego analiza y utiliza los datos del BLOB en función del tipo de petición. Note que el cliente está encargado de borrar el registro [SP Requests] una vez termina la petición.

El pequeño método de proyecto WAITING LOOP hace un bucle hasta un cierto número de tics:

  ` Método de proyecto WAITING LOOP
  ` WAITING LOOP ( Entero largo )
  ` WAITING LOOP ( Duración en tics )
 C_LONGINT($1)
 $vlStartTicks:=Tickcount
 Repeat
    IDLE
 Until((Tickcount-$vlStartTicks)>=$1)

Recordatorio: DELAY PROCESS no tiene efecto en el proceso principal. Si utiliza el método de proyecto WAITING LOOP, el proceso esperará la cantidad de tiempo necesaria, aunque la petición se origine desde el proceso del entorno usuario de un equipo cliente.

El método de proyecto SP SERVICES es el método ejecutado como procedimiento almacenado en el equipo servidor. La estructura general de este método, a continuación, es muy simple:

   Inicialización de una variable “stop”
   Repetir
      Búsqueda de las peticiones cuyo campo [SP Requests]reqStatus es igual a 1
      Para cada petición
         En función del tipo de petición, llamar una subrutina
            que guarde el resultado en el campo [SP Requests]reqData
         Cambiar el estado de la petición para que el cliente sepa lo que sucedió
      End for
      “Dormir” un poco antes de volver a comenzar
   Hasta que la variable “stop” se vuelva true

Este es el código fuente real:

  ` Método de proyecto SP SERVICES
  ` El procedimiento almacenado comienza
 vbStopSPServices:=False
  ` El procedimiento almacenado no necesita acceso en lectura escritura a las tablas...
 READ ONLY(*)
  ` ...excepto la tabla [SP Requests]
 READ WRITE([SP Requests])
 Repeat
  ` Búsqueda de las peticiones no procesadas aún
    QUERY([SP Requests];[SP Requests]reqStatus=1)
  ` Proceso de estas peticiones una por una
    For($vlRecord;1;Records in selection([SP Requests]))
  ` Si el registro de la petición está bloqueado, esperar hasta que esté desbloqueado
       While(Locked([SP Requests]))
  ` Espera un segundo antes de intentar nuevamente
          DELAY PROCESS(Current process;60)
  ` Trata de obtener acceso lectura-escritura
          LOAD RECORD([SP Requests])
       End while
  ` Asume que la petición se procesará con éxito
       [SP Requests]reqStatus:=0
       Case of
          :([SP Requests]reqType="Server Information")
             SP DO SERVER INFORMATION
          :([SP Requests]reqType="Volume List")
             SP DO VOLUME LIST
          :([SP Requests]reqType="Browse Directory")
             SP DO BROWSE DIRECTORY([SP Requests]reqParams)
  ` ...
  ` OTROS TIPOS DE PETICIONES PODRÍAN AÑADIRSE AQUÍ
  ` ...
          Else
  ` El tipo de petición es desconocido, devolver el error -1 (valor arbitrario)
             [SP Requests]reqStatus:=-1
       End case
  ` Forzar el estado de la petición a otro diferente de 1
  ` (en caso de una subrutina dar el valor 1)
       If([SP Requests]reqStatus=1)
          [SP Requests]reqStatus:=-3
       End if
  ` Actualizar el registro de la petición
       SAVE RECORD([SP Requests])
  ` Ir a la siguiente petición no procesada
       NEXT RECORD([SP Requests])
    End for
  ` Liberar el último registro procesado
    UNLOAD RECORD([SP Requests])
  ` Espere un segundo antes de continuar respondiendo peticiones
    DELAY PROCESS(Current process;60)
  ` Bucle hasta que se le ordene al procedimiento almacenado detener su ejecución
 Until(vbStopSPServices)

El método de proyecto SP SERVICES puede utilizarse como modelo para implementar novedosos servicios en una base. En esta sección, detallamos las subrutinas SP DO SERVER INFORMATION y SP DO VOLUME LIST. La subrutina SP DO BROWSE DIRECTORY (que toma como parámetro un parámetro enviado por el cliente en el campo [SP Requests]reqParams) no se trata en este documento.

Dependiendo del tipo de la petición, el método de proyecto SP SERVICES llama a una subrutina cuya tarea es guardar los datos resultantes en el campo [SP Requests]reqData. El almacenamiento del registro y el cambio del estado lo realizar el método de proyecto SP SERVICES.

Esta es la subrutina SP DO SERVER INFORMATION que guarda la información relativa al servidor en el BLOB. Otro método de proyecto extraerá los datos del BLOB en función del equipo cliente.

  ` Método de proyecto SP DO SERVER INFORMATION
 TEXT TO BLOB(Application version(*);[SP Requests]reqData;UTF8 C string)
 TEXT TO BLOB(Structure file;[SP Requests]reqData;UTF8 C string;*)
 TEXT TO BLOB(Data file;[SP Requests]reqData;UTF8 C string;*)
 PLATFORM PROPERTIES($vlPlatform;$vlSystem;$vlMachine)
 VARIABLE TO BLOB($vlPlatform;[SP Requests]reqData;*)
 VARIABLE TO BLOB($vlSystem;[SP Requests]reqData;*)
 VARIABLE TO BLOB($vlMachine;[SP Requests]reqData;*)

Esta es la subrutina SP DO VOLUME LIST, que guarda la información relativa a los volúmenes en el BLOB. Otro método de proyecto extraerá los datos del BLOB en función del equipo cliente.

  ` Método de proyecto SP DO VOLUME LIST
 VOLUME LIST($asVName)
 $vlSize:=Size of array($asVName)
 ARRAY REAL($arVSize;$vlSize)
 ARRAY REAL($arVUsedSpace;$vlSize)
 ARRAY REAL($arVFreeSpace;$vlSize)
 For($vlElem;1;$vlSize)
    VOLUME ATTRIBUTES($asVName{$vlElem};$arVSize{$vlElem};$arVUsedSpace{$vlElem}
    ;$arVFreeSpace{$vlELem})
 End for
 VARIABLE TO BLOB($asVName;[SP Requests]reqData)
 VARIABLE TO BLOB($arVSize;[SP Requests]reqData;*)
 VARIABLE TO BLOB($arVUsedSpace;[SP Requests]reqData;*)
 VARIABLE TO BLOB($arVFreeSpace;[SP Requests]reqData;*)

Con los métodos de proyecto genéricos Client post request y Client get result, el método de proyecto M_SERVER_INFORMATION muestra, en el equipo cliente, la información devuelta por el procedimiento almacenado. Este método puede estar asociado a un comando de menú o ser llamado, por ejemplo, desde el método de objeto de un botón:

  ` M_SERVER_INFORMATION
 C_BLOB(vxData)
 C_LONGINT($vlReqID;$vlErrCode;$vlOffset)
  ` Envío de la petición
 $vlReqID:=Client post request("Server Information")
  ` Prueba del estado de la petición y recepción del resultado
 $vlErrCode:=Client get result($vlReqID;->vxData;60)
  ` Si la petición termina con éxito, muestra el resultado
 If($vlErrCode=0)
  ` Extracción de la información resultante del BLOB
    $vlOffset:=0
    vsServerVersion:=BLOB to text(vxData;UTF8 C string;$vlOffset)
    vsStructureFile:=BLOB to text(vxData;UTF8 C string;$vlOffset)
    vsDataFile:=BLOB to text(vxData;UTF8 C string;$vlOffset)
    BLOB TO VARIABLE(vxData;$vlPlatform;$vlOffset)
    BLOB TO VARIABLE(vxData;$vlSystem;$vlOffset)
    BLOB TO VARIABLE(vxData;$vlMachine;$vlOffset)
  ` Análisis de las propiedades de la plataforma
    vs4DPlatform:="Versión de 4D Server desconocida"
    vsSystem:="Versión del sistema desconocida"
    vsMachine:="Equipo desconocido"
  `...
  ` Este es el código (no listado) que analiza $vlSystem y $vlMachine
  ` ( ver el ejemplo del comando PLATFORM PROPERTIES)
  ` ...
  ` Visualización de la información resultante
    DIALOG([SP Requests];"SERVER INFORMATION")
 Else
    ALERT("Error de petición "+String($vlErrCode))
 End if
  ` Ya no se necesita el BLOB
 CLEAR VARIABLE(vxData)

Este es el formulario [SP Requests];"SERVER INFORMATION" en ejecución:

Con los métodos de proyecto genéricos Client post request y Client get result, el método de proyecto M_SERVER_VOLUMES muestra, en el equipo cliente, la información en la lista de los volúmenes del servidor devuelta por el procedimiento almacenado. Este método puede estar asociado a un comando de menú o llamado, por ejemplo, desde el método de objeto de un botón:

  ` M_SERVER_VOLUMES
 C_BLOB(vxData)
  ` Envío de la petición
 $vlReqID:=Client post request("Volume List")
  ` Prueba del estado de la petición y recepción del resultado
 $vlErrCode:=Client get result($vlReqID;->vxData;120)
  ` Si la petición termina con éxito, muestra el resultado
 If($vlErrCode=0)
  ` Extracción de la información resultante del BLOB
    $vlOffset:=0
    BLOB TO VARIABLE(vxData;asVName;$vlOffset)
    BLOB TO VARIABLE(vxData;arVSize;$vlOffset)
    BLOB TO VARIABLE(vxData;arVUsedSpace;$vlOffset)
    BLOB TO VARIABLE(vxData;arVFreeSpace;$vlOffset)
    For($vlElem;1;Size of array(arVSize))
  ` Conversión de bytes en MB
       arVSize{$vlElem}:=arVSize{$vlElem}/1048576
       arVUsedSpace{$vlElem}:=arVUsedSpace{$vlElem}/1048576
       arVFreeSpace{$vlElem}:=arVFreeSpace{$vlElem}/1048576
    End for
  ` Visualización de la información resultante
    DIALOG([SP Requests];"VOLUME LIST")
 Else
    ALERT("Error de petición "+String($vlErrCode))
 End if
  ` Ya no es necesario el BLOB
 CLEAR VARIABLE(vxData)

Este es el formulario [SP Requests];"VOLUME LIST" en ejecución:



Ver también 

Importación con procedimientos almacenados (ejemplo)
Procedimientos almacenados

 
PROPIEDADES 

Producto: 4D
Tema: 4D Server y el lenguaje 4D

 
HISTORIA 

 
ARTICLE USAGE

Manual de 4D Server ( 4D v16)