API de script
A linguagem disponibiliza uma série de funções que provê suporte à chamada entre scripts. Esta funcionalidade permite que uma lógica comum seja utilizada por diversos scripts e está disponível ao usuário final somente pela Ferramenta de Scripts.
Para que seja possível executar ou agendar um script através da API é necessário configurar o identificador único do script a ser executado.
Executando scripts
A execução de um script é realizada utilizando a palavra reservada Scripts, seguida do identificador e método de execução:
Scripts.identificador.executar(parametros)
Scripts.calculos.somar.executar(parametros)
Scripts.dubai.consultas.funcionarios.executar(parametros)
identificador
Identificador único do script.
executar(parametros)
Função responsável pela execução do script.
parametros = [ p1 : 100, p2 : 200]
Scripts.somar.executar(parametros)
variaveis(Map)
Função responsável por enviar variáveis para outro script sem a necessidade de ter parâmetros no script que recebe essas variáveis.
O script de exemplo tem dois parâmetros do tipo arquivo, com os nomes arquivo e arquivo2, esses arquivos são enviados para o segundo script identificado por scriptb:
arquivos = [arquivo1: parametros.arquivo.valor, arquivo2: parametros.arquivo2.valor, val3:'teste teste 123']
Scripts.scriptb.variaveis(arquivos).executar();
No script que recebe as variáveis, os valores estão disponíveis da seguinte maneira:
Resultado.arquivo(variaveis.arquivo1)
Resultado.arquivo(variaveis.arquivo2)
imprimir variaveis.val3
O scriptb não precisa ter nenhum parâmetro para receber as variáveis e qualquer tipo pode ser passado por variaveis().
Outro exemplo seria um script principal que gera um arquivo csv com valores obtidos em execuções de outros três scripts:
Script principal
//Escrita
csv = Arquivo.novo('teste.csv', 'csv', [delimitador:';'])
csv.escrever('ID')
csv.escrever('NOME')
csv.escrever('SALARIO')
Scripts.geraarquivo.funcionarios1.variaveis(arquivo:csv).executar()
geraArquivo = {col1, col2, col3 ->
csv.novaLinha()
csv.escrever(col1)
csv.escrever(col2)
csv.escrever(col3)
}
Scripts.geraarquivo.funcionarios2.variaveis(retorno:geraArquivo).executar()
retorno = Scripts.componente3.executar()
imprimir retorno.variaveis.geraArquivo2(); // imprime o valor teste2 no log de execução do script principal
retorno.variaveis.geraArquivo(csv)
Resultado.arquivo(csv)
Script com o identificador geraarquivo.funcionarios1:
csv = variaveis.arquivo
criterio = Criterio.onde('nome').igual('Paulo Henrique')
dadosFuncionarios = Dados.dubai.v1.funcionarios
percorrer(dadosFuncionarios.busca(campos:"nome, id, salario", criterio: criterio)){
csv.novaLinha()
csv.escrever(item.id)
csv.escrever(item.nome)
csv.escrever(item.salario)
}
Script com o identificador geraarquivo.funcionarios2:
dadosFuncionarios = Dados.dubai.v1.funcionarios
criterio = Criterio.onde('nome').igual('Wellington')
id = '';
nome = '';
salario = '';
percorrer(dadosFuncionarios.busca(campos:"nome, id, salario", criterio: criterio)){
id = item.id
nome = item.nome
salario = item.salario
}
variaveis.retorno(id, nome, salario)
Script com o identificador componente3:
geraArquivo2 = {
retornar "teste2"
}
geraArquivo = {csv ->
csv.novaLinha()
csv.escrever('Valor 31')
csv.escrever('Valor 32')
csv.escrever('Valor 33')
}
Ao executar o script principal o arquivo csv é gerado.
Retorno dos scripts
A execução de um script através da API sempre irá produzir um resultado, Este resultado é representado da seguinte forma:
resultado = Scripts.somar.executar([ p1 : 100, p2 : 200])
As opções disponíveis em um resultado são: valor, vazio, variável(nome) e retornar.
valor
Recupera o valor retornado pelo script executado.
imprimir resultado.valor()
vazio
Verifica se o script invocado retornou algum resultado.
resultado = Scripts.somar.executar([ p1 : 100, p2 : 200])
se(resultado.vazio){
imprimir 'Nenhum resultado foi retornado pelo script somar'
}
variavel(nome)
Recupera o valor de uma variável declarada no script invocado.
resultado = Scripts.somar.executar([ p1 : 100, p2 : 200])
imprimir resultado.variavel('log') //Realizando soma
Note que a variável log foi declarada no conteúdo do script somar:
log = "Realizando soma"
retornar parametros.p1.valor + parametros.p2.valor
retornar
O retorno de um script é realizado utilizando o comando retornar:
retornar 'Retornando uma mensagem'
ret = [valor: 1, mensagem: 'Retornando um mapa']
retornar ret
Nas validações de certidões/alvarás do Cidadão Web, deve ser retornado:
ret = [resultado: 1, mensagem: 'Retornando um mapa']
Não sendo permitido o uso da seguinte forma:
se (x == 'teste')
{retornar resultado: 0}
senao
{ retornar resultado: 1, mensagem: 'Teste'] }
Ou seja, não sendo permitido dentro da condição "se" o retorno de mais de uma função retornar. Nestes casos, sendo indicado o uso no seguinte formato:
se (x == 'teste')
{ ret = [resutado:0] }
senao{
ret = [resultado:1, mensagem 'O ITBI está com pagamento pendente']
retornar ret;
Executando scripts em lotes
A execução de scripts em lote pode ser realizada através da criação de um script centralizador. Este script será responsável por orquestrar a execução dos demais scripts obedecendo a ordem cronológica de execução. Exemplo:
resultado = Scripts.somar.executar([ p1 : 100, p2 : 200])
Scripts.enviarEmailSoma.executar([valor: resultado.valor])
Scripts.enviarSmsSoma.executar([valor: resultado.valor])
Agendando scripts
O agendamento de um script é realizado utilizando a palavra reservada Scripts, seguida do identificador e método de agendamento:
Scripts.identificador.agendar(para) Scripts.identificador.agendar(parametros, para)
Scripts.calculos.somar.agendar(parametros, '10m')
Scripts.dubai.consultas.funcionarios.agendar(parametros, 2.horas)
identificador
Identificador único do script.
agendar([parametros], para)
Função responsável pelo agendamento do script.
parametros = [ p1 : 100, p2 : 200]
Scripts.somar.agendar(parametros, '15m')
Valores suportados no para
- Literal com a duração desejada. Ex: ('1m', '2h', etc)
- Data e hora especifica. Ex: Datas.data(2022, 6, 20)
- Duração usando a sintaxe do bfc-script. Ex: (1.minuto, 3.horas, 1.dia)
Regras para o agendamento
- Não pode ser para menos que um minuto e nem para mais que um mês
- Não pode encadear mais de 20 execuções agendadas (um script agendando outro ou ele mesmo sucessivamente)
- Só é permitido um agendamento por execução
- O agendamento ocorre somente no final da execução do script principal
Sugestões de uso
- Esperar o processamento de um lote enviado para algum serviço
- No lugar de parar a execução atual, utilizando o metodo
esperar
, basta agendar o mesmo ou outro script passando os parametros necessários para a consulta
- No lugar de parar a execução atual, utilizando o metodo
- Executar um processo incremental sem a necessidade de fazer um agendamento customizado
- De forma geral, em todos os lugares onde hoje se utiliza o
esperar
Componentes
Quando utilizar componentes?
Quando para resolver uma dada situação seja mais indicado fragmentar o script, seja por uma questão de organização ou de praticidade em ter funções com finalidades específicas devidamente separadas.
Por exemplo: Consideremos que um dado Tribunal de Contas exige bimestralmente a informação de todos os fornecedores de uma entidade via Web Service. Neste caso, poderiam existir os seguintes recursos:
Script principal, onde recebe os parâmetros para gerar as informações e enviá-las ao Tribunal de Contas;
Componente para identificar todos os fornecedores passíveis de envio ao Tribunal de Contas;
Componente para gerar o arquivo a ser enviado ao Tribunal de Contas;
Componente para enviar o arquivo ao Tribunal de Contas via Web Service;
Por que utilizar componentes?
São algumas vantagens na utilização dos componentes:
Melhor performance na execução do script: Por conta do recurso Exportar e Importar e também porque os componentes são executados exclusivamente a partir de um script que o invoca;
Organização de código: Por meio da fragmentação de código orientada ao objetivo fim do componente;
Privacidade de variáveis e closures (funções): Num componente é possível declarar variáveis e closures localmente, e então escolher quais serão expostos para quando o componente for importado por outro script;
Reutilização de código: Pode ser utilizado o mesmo componente em mais de um script;
Exemplos de utilização:
Exemplo 1: Este exemplo demonstra um componente que abstrai uma API REST.
Segue o código de um componente cujo identificador foi denominado restapi e que será chamado pelo script pai:
// variável local e privada ao componente
api = Http.servico('https://jsonplaceholder.typicode.com')
// closure privada ao componente
extractContent = { response ->
conteudo = -1
se (response.sucesso() && response.contemResultado()) {
conteudo = response.conteudo()
}
retornar conteudo
}
getPost = { id ->
extractContent(api.caminho("posts/$id").GET())
}
getComments = { idPost ->
extractContent(api.caminho("posts/$idPost/comments").GET())
}
Scripts.exportar(
buscarPublicacao: getPost,
buscarComentarios: getComments
)
O comando exportar é utilizado para definir quais recursos serão expostos pelo componente. Repare que as declarações que não foram exportadas permanecem privadas ao componente, permitindo assim uma modelagem mais robusta de funcionalidades comuns a vários scripts.
Segue o código do script pai que chama o componente acima:
api = Scripts.restapi.importar()
publicacao = api.buscarPublicacao(1)
se (publicacao != -1) {
imprimir "Publicacao: " + publicacao
}
comentarios = api.buscarComentarios(1)
se (comentarios != -1) {
imprimir "Comentarios: " + comentarios
}
A importação dos recursos de um componente é realizada utilizando a palavra reservada Scripts, seguido do identificador e o método de importação. O resultado é atribuído a uma variável, a partir da qual os recursos importados podem ser acessados.
Alternativamente, pode-se utilizar a palavra reservada importar passando como parâmetro o identificador do componente, no caso, fica assim:
api = importar "restapi"
Exemplo 2: Este exemplo trata de múltiplos componentes para um único Script Pai:
Existem 3 componentes:
Que simula uma calculadora;
Que executa um contador;
Que gera um log;
Componente 1: identificador ped.calculadora
add = { p1, p2 ->
p1 + p2
}
sub = { p1, p2 ->
p1 - p2
}
mul = { p1, p2 ->
p1 * p2
}
div = { p1, p2 ->
p1 / p2
}
exportar(
somar: add,
subtrair: sub,
multiplicar: mul,
dividir: div
)
Componente 2: identificador ped.contador
current = 0
inc = { amount = 1 -> current += amount }
dec = { amount = 1 -> current -= amount }
reset = { current = 0 }
get = { current }
Scripts.exportar(
incrementar: { inc(1) },
incrementarEm: inc,
decrementar: { dec(1) },
decrementarEm: dec,
zerar: reset,
atual: get
)
Componente 3: identificador ped.log
logFile = Arquivo.novo('log.txt')
logInfo = { text ->
logFile.escrever("INFO: $text")
logFile.novaLinha()
}
logError = { text ->
logFile.escrever("ERROR: $text")
logFile.novaLinha()
}
commit = {
imprimir "Adicionado log no resultado"
Resultado.arquivo(logFile, 'log.txt')
}
exportar(
info: logInfo,
erro: logError,
salvar: commit
)
Finalmente, o Script Pai:
calculadora = importar "ped.calculadora"
contador = importar "ped.contador"
imprimir "2 + 2 = ${calculadora.somar(2, 2)}"
imprimir "2 - 2 = ${calculadora.subtrair(2, 2)}"
imprimir "2 * 2 = ${calculadora.multiplicar(2, 2)}"
imprimir "2 / 2 = ${calculadora.dividir(2, 2)}"
imprimir "Inicio: " + contador.atual()
imprimir "+1: " + contador.incrementar()
imprimir "+10: " + contador.incrementarEm(calculadora.somar(5, 5))
imprimir "Zerado: " + contador.zerar()
//------------------------------------------------
log = importar "ped.log"
log.info("Iniciando execução")
percorrer(ate: 5) {
log.info("Executando passo #$indice")
}
log.erro("Erro na conversão dos valores")
log.salvar()