4D v16

Serviços baseados nos procedimentos armazenados (exemplo)

Página Inicial

 
4D v16
Serviços baseados nos procedimentos armazenados (exemplo)

Serviços baseados nos procedimentos armazenados (exemplo)  


 

 

No exemplo da seção Importação baseada nos procedimentos armazenados (exemplo), um procedimento armazenado se inicia e termina cada vez que se solicita uma operação de importação de dados. Neste exemplo, um procedimento armazenado é iniciado automaticamente quando inicia a base do servidor e pode ser iniciado e parado a vontade por qualquer 4D conectado a base. Logo como se executa, o procedimento armazenado pode responder de maneira assíncrona a múltiplos pedidos enviados pelos clientes conectados a base.

Enquanto a seção Importação baseada nos procedimentos armazenados (exemplo), mostra como otimizar um serviço 4D Server existente, este exemplo mostra como implementar serviços novos e personalizados disponíveis para todos as máquinas 4D client conectados. Além disso, este exemplo pode ser utilizado como modelo para a criação de seus próprios serviços.

O procedimento armazenado é lançado automaticamente pelo Método banco de dados On Server Startup:

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

Como o Método banco de dados On Server Startup lança ao método de projeto SP SERVICES como um procedimento armazenado, SP SERVICES começa a correr logo como a base se abre com 4D Server, tendo ou não clientes conectados à base. Na seguinte imagem, a janela de administração de 4D Server mostra o procedimento armazenado em execução quando nenhum cliente está conectado.

Este é o método de projeto START SP SERVICES:

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

Como o comando Execute on server atua como New process ao ser chamado na máquina servidor, o mesmo método (START SP SERVICES) pode ser utilizado na máquina servidor ou em uma máquina cliente para iniciar a vontade o método SP SERVICES como um procedimento armazenado na máquina servidor.

O método de projeto STOP SP SERVICES “ordena” parar ao método de projeto SP SERVICES.

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

Quando é iniciado o método de projeto SP SERVICES, da a variável processo vbStopSPServices o valor False e depois executa um laço até que esta variável Booleana se transforme em True. O comando , permite a todo processo usuário executado no servidor ou em uma máquina cliente modificar o valor da variável vbStopSPServices, e portanto parar o procedimento armazenado a vontade.

O procedimento armazenado deve poder receber pedidos de clientes e responder de maneira assíncrona em qualquer momento e sem importar a ordem. Uma maneira direta de assegurar esta comunicação é utilizar uma tabela.

A tabela [SP Requests] contém os seguintes campos:

  • [SP Requests]reqID é assinalado utilizando o comando Sequence number. Este campo identifica cada pedido de maneira única.
  • [SP Requests]reqType descreve o tipo do pedido.
  • [SP Requests]reqStatus pode tomar um dos seguintes valores:

ValorDescrição
1foi publicada a petição mas não foi processada.
0foi processado com êxito a petição.
< 0foi processada a petição mas ocorreu um erro.

Nota: Estes valores são escolhidos arbitrariamente para este exemplo, não são impostos por 4D.

  • [SP Requests]reqData é um BLOB que contém os dados da petição. Pode conter os dados enviados pela pessoa que solicita os dados devolvidos pelo procedimento armazenado ao requerente.
  • [SP Requests]reqParams contém eventualmente os valores dos parâmetros enviados pelo requerente ao procedimento armazenado.

A comunicação entre um processo cliente e um procedimento armazenado pode ser implantado utilizando os comandos GET PROCESS VARIABLE, SET PROCESS VARIABLE e VARIABLE TO VARIABLE. Por exemplo, esta solução utilizada na seção Importação baseada nos procedimentos armazenados (exemplo), como também no método de projeto STOP SP SERVICES listado anteriormente.

Aqui, o sistema deve permitir ao procedimento armazenado receber e reenviar as quantidades das variáveis de dados. Pode utilizar arrays, incluindo arrays de texto e imagem), mas há duas razões principais para preferir o emprego de uma tabela:

  • O algoritmo de gestão de petições sob os registros é mais fácil de implementar. Enviar uma petição desde uma máquina cliente consiste simplesmente em adicionar uma petição na tabela. Responder a petição desde o procedimento armazenado consiste simplesmente em modificar esta petição.
  • Como as petições se armazenam em uma tabela, são guardadas no disco. Portanto, se o tamanho de uma petição é importante, não será um problema na medida em que possa ser suprimido da memória (a diferença dos dados armazenados nos arrays).

O método de projeto Client post request é um método genérico para enviar uma petição:

  ` Método de projeto Client post request
  ` Client post request ( Cadeia { ; Texto } ) -> Inteiro longo
  ` Client post request ( Tipo de petição { ; Parâmetros } ) -> Número de petição
 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

O método devolve o número da petição, cuja unicidade está garantida pelo uso do comando Sequence number. Uma vez adicionado o registro a tabela [SP Requests], o cliente não têm que interrogar regularmente o campo [SP Requets]redStatus até que o procedimento armazenado termine de processar a petição.

O método de projeto Client get result é um método genérico para provar o estado da petição. Como foi explicado anteriormente, logo como o campo [SP Requets]redStatus se torna diferente de 1, o cliente sabe que o procedimento armazenado foi tratado (com êxito ou não) a petição.

  ` Método de projeto Client get result
  ` Client get result ( Inteiro longo ; ->BLOB {; Inteiro longo } ) -> Inteiro longo
  ` Client get result ( Número de petição ; ->Dados {; Duração } ) -> Código do erro
 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 perdeu o registro da petição
  ` Isto não deveria passar. Mas de todas formas estabelece o código de erro -2 (valor arbitrário)
       $0:=-2
    End if
  ` A petição ainda não foi processada
    If($0=1)
       WAITING LOOP($vlDelay)
    End if
 Until($0&NBSP;#&NBSP;1)
 READ ONLY([SP Requests])

Se a petição foi administrada com êxito pelo procedimento armazenado, o método copia o resultado (se existe) do registro ao BLOB cujo ponteiro foi passado como parâmetro. O método chamado depois analisa e utiliza os dados do BLOB em função do tipo de pedido. Note que o cliente está encarregado de apagar o registro [SP Requests] uma vez termina o pedido.

O pequeno método de projeto WAITING LOOP faz um laço até um certo número de tics:

  ` Método de projeto WAITING LOOP
  ` WAITING LOOP ( Inteiro longo )
  ` WAITING LOOP ( Tempo em tics )
 C_LONGINT($1)
 $vlStartTicks:=Tickcount
 Repeat
    IDLE
 Until((Tickcount-$vlStartTicks)>=$1)

Lembrança: DELAY PROCESS não tem efeito no processo principal. Se utiliza o método de projeto WAITING LOOP, o processo esperará a quantidade de tempo necessário, ainda que o pedido tenha origem desde o processo do ambiente usuário de uma máquina cliente.

O método de projeto SP SERVICES é o método executado como procedimento armazenado na máquina servidor. A estrutura geral deste método, a continuação,  muito simples:

   Inicialização de uma variável “stop”
   Repetir
      Pesquisa das petições cujo campo [SP Requests]reqStatus é igual a 1
      Para cada petição
         Em função do tipo de petição, chamar uma subrotina
            que guarde o resultado no campo [SP Requests]reqData
         Mudar o estado da petição para que o cliente saiba que passou
      End for
      “Dormir” um pouco antes de voltar a começar
   Até que a variável “stop” se torne true

Este é o código fonte real:

  ` Método de projeto SP SERVICES
  ` O procedimento armazenado começa
 vbStopSPServices:=False
  ` O procedimento armazenado não necessita acesso em leitura escritura as tabelas...
 READ ONLY(*)
  ` ...exceto a tabela [SP Requests]
 READ WRITE([SP Requests])
 Repeat
  ` Pesquisa dos pedidos ainda não processados
    QUERY([SP Requests];[SP Requests]reqStatus=1)
  ` Processo destas petições uma por uma
    For($vlRecord;1;Records in selection([SP Requests]))
  ` Se o registro da petição está bloqueado, esperar até que esteja desbloqueado
       While(Locked([SP Requests]))
  ` Esperar um segundo antes de tentar novamente
          DELAY PROCESS(Current process;60)
  ` Trata de obter acesso leitura-escritura
          LOAD RECORD([SP Requests])
       End while
  ` Assume que a petição será processada com sucesso
       [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)
  ` ...
  ` OUTROS TIPOS DE PETIÇÕES PODERIAM SER INCLUÍDAS AQUI
  ` ...
          Else
  ` O tipo de petição é desconhecido, devolver o erro -1 (valor arbitrário)
             [SP Requests]reqStatus:=-1
       End case
  ` Forçar o estado da petição a outro diferente de 1
  ` (em caso de uma subrotina dar o valor 1)
       If([SP Requests]reqStatus=1)
          [SP Requests]reqStatus:=-3
       End if
  ` Atualizar o registro da petição
       SAVE RECORD([SP Requests])
  ` Ir a seguinte petição não processada
       NEXT RECORD([SP Requests])
    End for
  ` Liberar o último registro processado
    UNLOAD RECORD([SP Requests])
  ` Espere um segundo antes de continuar respondendo petições
    DELAY PROCESS(Current process;60)
  ` Bucle até que seja ordenado ao procedimento armazenado parar sua execução
 Until(vbStopSPServices)

O método de projeto SP SERVICES pode ser utilizado como modelo para implementar serviços inovadores em uma base. Nesta seção, detalhamos as subrotinas SP DO SERVER INFORMATION e SP DO VOLUME LIST. A subrotina SP DO BROWSE DIRECTORY (que toma como parâmetro um parâmetro enviado pelo cliente no campo [SP Requests]reqParams) não se trata neste documento.

Dependendo do tipo da petição, o método de projeto SP SERVICES chama a uma subrotina cuja tarefa é guardar os dados resultantes no campo [SP Requests]reqData. O armazenamento do registro e a mudança do estado a realizar o método de projeto SP SERVICES.

Esta é a subrotina SP DO SERVER INFORMATION que guarda a informação relativa ao servidor no BLOB. Outro método de projeto extrairá os dados do BLOB em função da máquina cliente.

  ` Método de projeto 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 é a subrotina SP DO VOLUME LIST, que guarda a informação relativa aos volumes no BLOB. Outro método de projeto extrairá os dados do BLOB em função da máquina cliente.

  ` Método de projeto 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;*)

Com os métodos de projeto genéricos Client post request e Client get result, o método de projeto M_SERVER_INFORMATION mostra, na máquina cliente, a informação devolvida pelo procedimento armazenado. Este método pode estar associado a um comando de menu ou ser chamado, por exemplo, desde o método de objeto de um botão:

  ` M_SERVER_INFORMATION
 C_BLOB(vxData)
 C_LONGINT($vlReqID;$vlErrCode;$vlOffset)
  ` Envio do pedido
 $vlReqID:=Client post request("Server Information")
  ` Prova do estado do pedido e recepção do resultado
 $vlErrCode:=Client get result($vlReqID;->vxData;60)
  ` Caso o pedido termina com sucesso, é mostrado o resultado
 If($vlErrCode=0)
  ` Extração da informação resultante do 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álises das propriedades da plataforma
    vs4DPlatform:="Versão de 4D Server desconhecida"
    vsSystem:="Versão do sistema desconhecida"
    vsMachine:="Computador desconhecido"
  `...
  ` Este é o código (não listado) que analisa $vlSystem e $vlMachine
  ` ( ver o exemplo do comando PLATFORM PROPERTIES)
  ` ...
  ` Visualização da informação resultante
    DIALOG([SP Requests];"SERVER INFORMATION")
 Else
    ALERT("Erro de pedido "+String($vlErrCode))
 End if
  ` Não é mais necessário o BLOB
 CLEAR VARIABLE(vxData)

Este é o formulário [SP Requests];"SERVER INFORMATION" em execução:

Com os métodos de projeto genéricos Client post request e Client get result, o método de projeto M_SERVER_VOLUMES mostra, na máquina cliente, a informação na lista dos volumes do servidor devolvidos pelo procedimento armazenado. Este método pode estar associado a um comando de menu ou chamado, por exemplo, desde o método de objeto de um botão:

  ` M_SERVER_VOLUMES
 C_BLOB(vxData)
  ` Envio do pedido
 $vlReqID:=Client post request("Volume List")
  ` Prova do estado da petição e recepção do resultado
 $vlErrCode:=Client get result($vlReqID;->vxData;120)
  ` Se a petição termina com sucesso, mostra o resultado
 If($vlErrCode=0)
  ` Extração da informação resultante do 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))
  ` Conversão de bytes em MB
       arVSize{$vlElem}:=arVSize{$vlElem}/1048576
       arVUsedSpace{$vlElem}:=arVUsedSpace{$vlElem}/1048576
       arVFreeSpace{$vlElem}:=arVFreeSpace{$vlElem}/1048576
    End for
  ` Visualização da informação resultante
    DIALOG([SP Requests];"VOLUME LIST")
 Else
    ALERT("Erro de petição "+String($vlErrCode))
 End if
  ` Já não é necessário o BLOB
 CLEAR VARIABLE(vxData)

Este é o formulário [SP Requests];"VOLUME LIST" em execução:



Ver também 

Importação baseada nos procedimentos armazenados (exemplo)
Procedimentos armazenados

 
PROPRIEDADES 

Produto: 4D
Tema: 4D Server e a linguagem 4D

 
HISTÓRIA 

 
ARTICLE USAGE

Manual de 4D Server ( 4D v16)