Pular para o conteúdo principal
Version: 4.21.0

Gatilhos e Customizações

Desenvolvimento de Adapters para Workflow de Trabalho

Durante a modelagem de um processo no Fusion, podem demanda o desenvolvimento de adapters de Workflow. Ao construir um Workflow, algumas características são necessárias para automatizar o processo, tais como intrações e validações.

Estes possuem características específicas dentro do contexto do Workflow e devem implementar a classe AdapterInterface que possui métodos obrigatórios, o método start() e o back().

Normalmente, o código para adapters de Workflow é desenvolvido dentro destes dois métodos.

Adição de Adapters ao Modelo de Processo

Para incluir um adapter no processo, ele deve ser incluído na modelagem, em uma atividade do tipo Script.

Para editar uma atividade de Script, basta clicar sobre a atividade no icone de configurações e selecionar a opção "Script":

63

Após selecionar "Script", as características do Painel de Propriedades serão alteradas para esse contexto.

No Painel de Propriedades, preencha o campo "Descrição" e no o campo "Tipo de Script" defina o valor padrão que é "Adapter".

Na propriedade "Classe Java" informe o espaço de nomes da Classe Java desenvolvida.

Atenção

É importante ter cuidao com o namespace, pois qualquer erro impedirá o funcionamento do Adapter

64

65

A maneira mais segura de copiar o namespace no Eclipse é posicionar o cursor sobre o nome da classe e clicar com o botão direto do mouse, depois selecionar o item "Copy Qualified Name". O Eclipse copiará para área de transferência o namespace da classe.

Em seguida, você vai colar a informação copiada na propriedade "Classe Java" no Painel de Propriedades, dessa forma, a possibilidade de erros de digitação será anulada.

66

Exemplos de Uso

Expedição de Documentos

Este exemplo inicia uma expedição de documento, para uma lista de Destinatarios selecionados.

public class AdapterIniciaExpedicao implements AdapterInterface
{
@Override
public void start(Task task, EntityWrapper wrapper, Activity activity)
{
wrapper.setValue("autorExped", PortalUtil.getCurrentUser());

List<NeoObject> selecDestinatarios = wrapper.findGenericValue("selecDestinatarios");

List<NeoObject> listaDestinatarios = wrapper.findGenericValue("listaDestinatarios");

for (NeoObject uDestinatario : selecDestinatarios)
{
NeoObject oNovoDest = AdapterUtils.createNewEntityInstance("listaDestinatarios");

EntityWrapper wNovoDest = new EntityWrapper(oNovoDest);

wNovoDest.findField("destinatario").setValue(uDestinatario);

PersistEngine.persist(oNovoDest);

listaDestinatarios.add(oNovoDest);
}

wrapper.findField("listaDestinatarios").setValue(listaDestinatarios);

NeoObject tramitarCorrespondenciaInterna = wrapper.findGenericValue("tramitarCorrespondenciaInterna");

if (tramitarCorrespondenciaInterna != null)
{
String titulo = wrapper.findGenericValue("tramitarCorrespondenciaInterna.titulo");
String resAssunto = wrapper.findGenericValue("tramitarCorrespondenciaInterna.resAssunot");
NeoObject classificacao = wrapper.findGenericValue("tramitarCorrespondenciaInterna.categProgAtiv");

wrapper.findField("tituloBreve").setValue(titulo);
wrapper.findField("resumoAssunto").setValue(resAssunto);
wrapper.findField("categorias").setValue(classificacao);
}
}

@Override
public void back(EntityWrapper wrapper, Activity activity)
{

}

}

Enviar E-mail Customizado com Anexo

Este exemplo procura informações no formulário e anexa um arquivo no e-mail.

public class AdapterEnviaEmailComAnexos implements AdapterInterface {

@Override
public void start(Task task, EntityWrapper wrapper, Activity task) {

String title = Orcamento.ASSUNTO;
String texto = wrapper.findGenericValue("resposta");

NeoUser solicitante = wrapper.findGenericValue("solicitante");

List<NeoUser> listUsuarios = new ArrayList<NeoUser>();
listUsuarios.add(solicitante);

String anexos = "anexos";
String anexo = "anexo";

CustomSendMailUtils.SendMail(wrapper, listUsuarios, title, texto, anexos, anexo);
}

@Override
public void back(EntityWrapper wrapper, Activity task) {

}

}

Usando o Agendador de Tarefas

Essa funcionalidade permite que as tarefas sejam executadas automaticamente de acordo com o parâmetro de tempo previamente definido. Com isso, é possível criar tarefas para sincronizar bancos, iniciar processos de forma automática, limpar logs e etc.

As tarefas a serem executadas devem estar contidas em um adapter java e devem implementar a interfaceCustomJobAdapter. O código a ser executado estará dentro do médoto execute.

67

Para agendar uma tarefa, clique em "Novo", adicione um nome e uma descrição para a tarefa e defina o campo "Habilitado" como "Sim".

No campo "Adapter", informe o namespace da classe que será executada. Em Trigger você realizará a configuração do mesmo, clicando em "Novo" e preenchendo os campos necessários para repetir a execução agendada.

68

Adapter do Agendados de Tarefas - Importador Simplificado

O código abaixo exemplifica a estrutura de um adapter para o Agendador de Tarefas.

Neste exemplo, os dados de uma tabela externa estão sendo importados para uma forma dinâmica do Fusion.

public class ExempleSchedulerImportsData implements CustomJobAdapter
{
@Override
public void execute(CustomJobContext ctx)
{
// TODO Auto-generated method stub
List<NeoObject> listProduct = (List<NeoObject>)
PersistEngine.getObjects(AdapterUtils.getEntityClass("AdverntureProducts"));

for(NeoObjects product : listProduct)

{
// External E-form data
EntityWrapper wrapperProducts = new EntityWrapper(product);

String description = (String) wrapperProducts.findField("name").getValue();
String productNumber = (String) wrapperProducts.findField("productnumber").getValue();

// Instantiable object in Fusion and set values
NeoObject productFusion = AdapterUtils.createnewEntityInstance("Product");
EntityWrapper weapperProductFusion = new EntityWrapper(productFusion);

wrapperProductFusion.findField("code").setvalue(productNumber);
wrapperProductFusion.findField("description,").setvalue(productNumber);
}
}
}

REST

A necessidade de troca de informações entre aplicações motivou diferentes abordagens para "integração de dados", desde soluções simples e questionáveis como a utilização de um banco de dados compartilhado ou realizar troca de arquivos, até soluções mais elaboradas que utilizam objetos distribuídos.

Em diversos casos não há apenas a integração de sistemas diferentes, mas a distrubuição de um único sistema em várias partes também pode ser integrada da mesma forma.

A solução de integração denominada WebService, que é bastante simples de implementar, é a mais utilizada atualmente.

Abaixo encontramos um exemplo de REST.

package com.neomind.fusion.custom.rest;

public class UserVO
{
private String name;
private Long age;

public String getName()
{
return name;
}

public void setName(String name)
{
this. name = name;
}

public Long getAge()
{
return age;
}

public void setAge(Long age)
{
this. age = age;
}
}
package com.neomind.fusion.custom.rest;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import com.neomind.fusion.entity.EntityWrapper;
import com.neomind.fusion.portal.PortalUtil;
import com.neomind.fusion.security.NeoUser;
import com.neomind.fusion.custom.rest.UsuarioVO;

@Path("/main")
public class MainService
{
// Simple call without parameters
@GET
@Path("/ReturnsLoggedUser")
public String returnLoggedUber()
{
NeoUser userLogged = PortalUtil.getCurrentUser();
return userLogged.getFullName();
}
// Call receiving a parameter via QueryParam
//http://localhost:8080/fusion/service/main/CampoUsuarioQParam?nomeCampo=<campo>
@GET
@Path("/ReturnsUserFieldQParam")
public Object ReturnsUserFieldQParam( @QueryParam( "nameField") String nameField)
{
NeoUser userLogged = PortalUtil.getCurrentUser();
EntityWrapper wrapper = new EntityWrapper(userLogged);
Object returns = wrapper.findGenericValue(nameField );
return returns;
}
// Call receiving a parameter via PathParamm
//http://localhost:8080/fusion/services/main/RetornaCampoUsuarioPParam?nomeCampo=<campo>
@GET
@Path("ReturnUserFieldPParam/{nameField}")
public Object ReturnUserFieldPParam(@PathParam ("nameField" ) String nameField)
{
NeoUser userLogged = PortalUtil.getCurrentUser();
EntityWrapper wrapper = new EntityWrapper(userLogged);
Object returns = wrapper.findGenericValue(nameField );
return returns;
}
// Sending a JSON
@GET
@Path("/ReturnsUserFieldJson")
@Procudes(MediaType. APPLICATION_JSON + ";charset=utf-8")
public UserVO returnsLoggedUserJson()
{
NeoUser loggedUser = PortalUtil.getCurrentUser();

UserVO user = new UserVO();
user.setName( loggedUser.getFullName());
user.setAge(30L);

return user;
}
// Receiving a JSON
@POST
@Path("/SaveUser")
@Produces(MediaType. APPLICATION_JSON + ";charset=utf-8")
@Consumes(MediaType. APPLICATION_JSON + ";charset=utf-8")
public UserVO saveUber(UserVO user)
{
return user;
}
}

SOAP

Assista um vídeo detalhado a respeito desse tema neste link.

Personalização de Modelos de E-mail

O tamplate de e-mail é um JSP (Java Server Pages), que utiliza tags em HTML com Java embutidos no código fonte.

Abaixo podemos ver como é a estrutura dele:

<%@ page contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>

<%@ taglib uri="/WEB-INF/mail.tld" prefix="mail" %>
<%@ taglib uri="/WEB-INF/workflow.tld" prefix="wf" %>
<%@ taglib uri="/WEB-INF/portal.tld" prefix="portal" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

<%

/*
* Aqui é onde fica a parte do "backend" do JSP
*/

%>

<jsp:include page="/mail/top.jsp"/>

<mail:title title="<%= "Titulo do Email" %>"/>

<p class="titulo_1" style="font-family: Helvetica, Arial, sans-serif; color: #6b7486; line-height: 25px;">

<%--
Aqui é onde todos os codigo em HTML vão ficar para serem renderizados ao enviar o email
--%>


<jsp:include page="/mail/bottom.jsp"/>

E agora, podemos ver abaixo um exemplo do e-mail renderizado:

69

Como funciona?

Para construir um tamplate customizado, én ecessário montar uma classe java que faz a chamada do envio de e-mail. Esta classe pode ser do tipo: AdapterInterface, EntityAdapter, etc.

A seguir temos a estrutura de um e-mail simples apenas para mostrar como é o funcionamento do backend em Java e como é feito para passar os parâmetros para o JSP:

public class EnviarEmailAdapter implements AdapterInterface
{
@Override
public void start(Task origin, EntityWrapper processEntity, Activity activity)
{

String eMail = "";
HashMap<String, Object> paramMap = new HashMap<>();

String tituloAssunto = (String) processEntity.findValue("TituloAssunto");
String informativo = (String) processEntity.findValue("Informativo");

paramMap.put("tituloAssunto", tituloAssunto);
paramMap.put("informativo", informativo);

List<NeoObject> neoObjectList = (List<NeoObject>) processEntity.findValue("ListaDeUsuarios");

for (NeoObject xTo : neoObjectList)
{
if (xTo instanceof NeoUser)
{
NeoUser noUsuario = (NeoUser) xTo;
eMail = noUsuario.getEmail();
paramMap.put("targetName", noUsuario.getFullName());
}

MailEngine.getInstance().sendEMail(eMail, "mail/GenericTemplate.jsp", paramMap);
}
}

@Override
public void back(EntityWrapper processEntity, Activity activity)
{
}
}

Como enviar as informações par o JSP?

Através de um HashMap é possível mapear cada informação que seja necessária passar para o JSP.

No exemplo acima possuímos três informações principais:

  • Título do Assunto
  • Informativo
  • O nome do usuário que será enviado o e-mail

Agora que sabemos o que passar no e-mail, temos que criar a chamada da Engine do e-mail do Fusion:

MailEngine.getInstance().sendEMail(eMail, "mail/GenericTemplate.jsp", paramMap);

Existem duas informações vitais na chamada do método acima que são obrigatórias:

  • O primeiro parâmetro é o destinatário. Nesse parâmetro podemos passar dois tipos de informações: o e-mail ou até mesmo o NeoUser.
  • O segundo parâmetro é o template que será usado para enviar.
  • O terceiro parâmetro (opcional) é o HashMap, ele não precisa necessariamente estar na chamada do método, mas neste caso como queremos passar informações para o JSP, manteremos.

No JSP vamos pegar as informações do backend via request:

<%@page import="com.neomind.fusion.i18n.I18nUtils" %>
<%@ page contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>

<%@ taglib uri="/WEB-INF/mail.tld" prefix="mail" %>
<%@ taglib uri="/WEB-INF/workflow.tld" prefix="wf" %>
<%@ taglib uri="/WEB-INF/portal.tld" prefix="portal" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

<%
String titleEmail = "Portal Corporativo - Email de Notificação";
String titleAssunto = (String) request.getAttribute("tituloAssunto");
String informativo = (String) request.getAttribute("Informativo");
String targetName = (String) request.getAttribute("targetName");
%>

<jsp:include page="/mail/top.jsp"/>

<mail:title title="<%= titleEmail %>"/>

<p class="titulo_1" style="font-family: Helvetica, Arial, sans-serif; color: #6b7486; line-height: 25px;">

<%=I18nUtils.getString("hello")%> <span style="font-weight: bold"> <%= targetName %></span>,
<br/>
<%=titleAssunto%>
<br/>
<%=informativo%>
<br/>
</p>

<jsp:include page="/mail/bottom.jsp"/>

E agora podemos visualizar o e-mail renderizado:

70

Como anexar documentos?

Para anexar documentos, usaremos a mesma forma de envio, apenas será adicionado uma classe custom que será responsável por todo o envio do e-mail.

A classe EnviarEmailAdapter ficou assim:

public class EnviarEmailAdapter implements AdapterInterface
{
@Override
public void start(Task origin, EntityWrapper processEntity, Activity activity)
{

String tituloAssunto = (String) processEntity.findValue("TituloAssunto");
String informativo = (String) processEntity.findValue("Informativo");

List<NeoObject> neoObjectList = (List<NeoObject>) processEntity.findValue("ListaDeUsuarios");

CustomSendMailUtils.SendMail(processEntity, neoObjectList, tituloAssunto, informativo, "ListaDeAnexos", "Anexo");
}

@Override
public void back(EntityWrapper processEntity, Activity activity)
{

}
}

A nova classe CustomSendMailUtils:

public class CustomSendMailUtils
{

private static Log log = LogFactory.getLog(CustomSendMailUtils.class);

public static void SendMail(EntityWrapper wrapper, List<NeoObject> to, String title, String text, String attachsFieldName, String attachFieldName)
{

String eMail = null;

Map<String, Object> paramMap = new HashMap<>();
paramMap.put("title", title);
paramMap.put("texto", text);

if (attachsFieldName != null && attachFieldName != null)
{
List attachs = getAttachedDoc(wrapper, attachsFieldName, attachFieldName);

if (attachs.size() > 0)
{
paramMap.put("attachList", attachs);
}
}


for (NeoObject xTo : to)
{
if (xTo instanceof NeoUser)
{
NeoUser noUsuario = (NeoUser) xTo;
eMail = noUsuario.getEmail();
paramMap.put("targetName", noUsuario.getFullName());
}

MailEngine.getInstance().sendEMail(eMail, "mail/GenericTemplate.jsp", paramMap);
}

}
}

A única diferença é que se você deseja colocar um anexo no HashMap, você precisa passar como parâmetro o attachList como uma lista do neoId dos anexos.

    private static List getAttachedDoc(EntityWrapper wrapper, String attachsField, String attachFieldName)
{
List<String> finale = new ArrayList<>();

List<NeoObject> listAnexos = wrapper.findGenericValue(attachsField);

if (listAnexos != null && listAnexos.size() > 0)
{
for (NeoObject objAnexo : listAnexos)
{
EntityWrapper wrapperAnexo = new EntityWrapper(objAnexo);
String nomeArquivo = ((NeoFile) wrapperAnexo.findGenericValue(attachFieldName)).getName();
log.info(nomeArquivo);
NeoFile doc = PersistEngine.getObject(NeoFile.class, new QLRawFilter("name = '" + nomeArquivo + "'"));
if (doc != null)
{
finale.add(String.valueOf(doc.getNeoId()));
}
}
}
return finale;
}

Este exemplo é um geral que possuimos como parâmetro o EntityWrapper, o attachField que é o campo lista no formulário princiapl e o attachFieldName que é o campo onde o anexo está localizado:

CustomSendMailUtils.SendMail(processEntity, neoObjectList, tituloAssunto, informativo, "ListaDeAnexos", "Anexo");

No caso "ListaDeAnexos" é a nossa lista e o "Anexo" é o campo arquivo dentro da nossa "ListaDeAnexos".

Customização do Exibir Registros (ShowRecordsAdapter)

O Exibir Registros exibe os dados de uma entidade em formato de lista (grid).

Por padrão, as colunas exibidas nessa lista são definidas pela configuração da entidade. Contudo, em alguns cenários, é necessário controlar dinamicamente quais campos serão exibidos, considerando regras de negócio, o usuário logado ou o contexto de uso da aplicação.

Para isso, o Fusion oferece a extensão ShowRecordsAdapter.

Esse recurso funciona como um interceptor, permitindo que as colunas exibidas na lista deixem de ser fixas e sejam controladas por lógica de negócio personalizada, substituindo ou complementando a configuração padrão da entidade.

Como funciona?

Durante o carregamento da tela de Exibir Registros:

  1. O sistema verifica se a EntityInfo da entidade possui um customAdapter configurado.
  2. Se configurado, o sistema instancia essa classe e cria um objeto ShowRecordsContext com informações sobre:
  • A entidade
  • O usuário logado
  • Logs para auditoria
  1. O método getGridColumns é executado, e a lista de colunas retornada define quais campos serão mostrados na grid.
Nota

Se ocorrer qualquer problema, como a falta do adapter ou erro na execução, o sistema usa o layout padrão de colunas da entidade.

Interface ShowRecordsAdapter

Para customizar as colunas, é necessário implementar a interface ShowRecordsAdapter, que possui o método obrigatório:

List<String> getGridColumns(ShowRecordsContext context);

ShowRecordsContext

O ShowRecordsContext contém informações importantes, como:

  • EntityInfo da entidade
  • Usuário logado
  • Logger
  • Contexto da execução do Exibir Registros

Exemplos de uso:

  • Alterar colunas conforme o perfil do usuário
  • Exibir ou ocultar colunas com base em condições, como status de um registro
  • Exibir diferentes grids para a mesma entidade

Exemplo de Implementação

Aqui está um exemplo básico de como implementar o ShowRecordsAdapter:

package com.neomind.fusion.custom.showrecords;

import com.neomind.fusion.entity.ShowRecordsAdapter;
import com.neomind.framework.fusion.modules.eform.engine.adapter.ShowRecordsContext;
import java.util.List;

public class ConsensoShowRecordsAdapter implements ShowRecordsAdapter
{
@Override
public List<String> getGridColumns(ShowRecordsContext context)
{
// Logando informações de contexto
context.getLogger().info(
"Definindo colunas para a entidade {} e usuário {}",
context.getEntityInfo().getTypeName(),
context.getCurrentUser().getLogin()
);

// Retorna os códigos dos campos que serão exibidos como colunas
return List.of("Texto", "DataCriacao", "Status");
}
}

Configuração do Adapter na Entidade

Após implementar a classe, siga esses passos:

  1. Garanta que a classe esteja no classpath do Fusion.
  2. Acesse a configuração da EntityInfo da entidade que você quer customizar.
  3. No campo customAdapter, informe o nome completo da classe (FQN), como neste exemplo:
com.neomind.fusion.custom.showrecords.ConsensoShowRecordsAdapter

Agora, sempre que a grid dessa entidade for carregada, o Fusion usará o adapter para definir as colunas a serem exibidas.

Boas Práticas

  • Sempre retorne códigos de campos válidos da entidade.
  • Utilize o logger do contexto para facilitar diagnósticos.
  • Evite lógica complexa ou consultas demoradas dentro do adapter.
  • Nunca retorne listas vazias sem motivo (isso pode gerar erros inesperados).

Resumo

ItemDescrição
InterfaceShowRecordsAdapter
Método obrigatóriogetGridColumns(ShowRecordsContext)
ConfiguraçãoCampo customAdapter da EntityInfo
ObjetivoCustomizar dinamicamente as colunas no Exibir Registros
FallbackUsar o layout padrão da entidade se houver erro