terça-feira, 18 de maio de 2021

Versão 21.4.0-Final

   

Introdução
Nesse post vou mostrar as principais novidades da versão 21.4.0, algumas correções e pequenas alterações.

Alterações

Além das implementações descritas acima foram feitas algumas alterações:
- Alterado o CrudDao para não remover itens de detalhe no change
-Alteração da versão do Primefaces da 8.0 para 10.0 mais informações em: https://primefaces.github.io/primefaces/10_0_0/#/../migrationguide/migrationguide
- Adicionado atributo others no @JArchSearchFieldLookup para permitir colocar "V2" quando o estiver dentro de um e:filterSearch com outro lookup dentro, assim ele vai utilizar o e:_lookup2
- Adicionado evento change no e:inputTextMoney
- Alterado o componente e:filterSearch para quando for componente definido com zeros a esquerda para permitir somente a digitação de números
- Alterado a validação de email para verificar um ponto final após o @
- Adicionado o atributo styleClass no e:inputTextInteger
- 
Refatoração na API ExcelUtils separando XLS de XLSX

Correções

Além das alterações descritas acima esta versão contempla algumas correções:
- Correções nos campos de valores para adequar ao Primefaces X (separador de milhar e decimal)
- Acerto no LazyDataModelPaginator para utilizar o IIdentity no lugar do IBaseEntity
- Removido o métodp preencheDataModelList do IBaseFilterSelectController adicionado o fillDataModelList em seu lugar
- Corrigido o ícone do JavaScriptUtils.showMessageBodyWarningNoRedirect() e JavaScriptUtils.showMessageBodyWarningRedirect() de ERRO para WARNING 
- Ajuste na API do Excel para gerar não gerar linhas em branco quando não houver título
- Ajuste nas colunas de a:selectOneMenu do e:filterSearch para ajustar com o tamanho disponível e não com o tamanho do maior item da lista
- Ajuste na localização de mensagens do properties (bundle e ValidationMessages)
- Acerto no e:filterSearch para reconhecer actions do e:lookup com o sufixo Controller
- Correção no YearMonthJsfConverter para tratar exceção de mês/ano inválido

Implementações

Além das alterações descritas acima esta versão contempla algumas implementações:
- Adicionado novo componente e:inputTextRate para utilização em percentuais
- Adicionado QrCodeUtils para contemplar a geração de QRCode em arquivo

Conclusão

Essa versão contempla algumas melhorias e correções. É recomendável a atualização para essa nova versão.

Até mais,

quarta-feira, 7 de abril de 2021

Versão 21.3.0-Final

  

Introdução
Nesse post vou mostrar as principais novidades da versão 21.3.0, algumas correções e pequenas alterações.

Alterações

Além das implementações descritas acima foram feitas algumas alterações:
- Alterado o ClientJpql para que o construtor possa ser reutilizado em heranças (protected)
- Alterado a geração do JpqlBuilder para poder utilizar implementações de métodos na própria classe (como método de instância)

Correções

Além das alterações descritas acima esta versão contempla algumas correções:
- Correção nos atributos de ordenacao para order nos componentes e:divDataDetailTab, e:divListDatatable e e:divListDatatableSimple
- Correção no e:lookup quando carregado de dentro de outro e:lookup. Criado o e:_lookup replicado do lookup para ser usado dentro do e:filterSearch
- Acerto no FormataNumeroUtils.formata para tratar o parâmetro null (formatar como ZERO)

Conclusão

Essa versão contempla algumas melhorias e correções. É recomendável a atualização para essa nova versão.

Até mais,

terça-feira, 2 de março de 2021

Versão 21.2.0-Final

 

Introdução
Nesse post vou mostrar as principais novidades da versão 21.2.0, algumas correções e pequenas alterações.

Implementação
Segue abaixo as implementações dessa versão:
- Adicionado o preenchimento do combo de tarefas na primeira vez que acessar a tela de lista de tarefas
- Adicionado nova anotação @JArchColumnsDataTable para agrupar as anotações @JArchColumnDataTable
- Adicionnado a opção de between na biblioteca de JPQL
- Adicionado na e:divListDatatable os atributos hideSeparatorActionDynamic e hideSeparatorActionDownload para ser possível condicionar o separador do menu de ações

Alterações

Além das implementações descritas acima foram feitas algumas alterações:
- Alterado o atributo facade para service e manager para dao das anotações de geração de código
- Alterado regras de validações de compilação: 
    1. Anotações @JArchSearchs (Field, Combo, Check, etc) para não aceitar o atributo classEntity  quando estiver dentro de um @JArchSearchTab 
    2. Anotações @JArchSearchs (Field, Combo, Check, etc) para obrigar o preenchimento do atributo classEntity quando não estiver dentro do @JArchSearchTab 
    3. Anotações @JArchSearchs (Field, Combo, Check, etc) para obrigar o preenchimento do atributo field ou whereJpa 
    4. Anotações @JArchColumnDataTable para não aceitar o atributo classEntity quando estiver dentro de um @JArchColumnsDataTable 
    5. Anotações @JArchColumnDataTable para obrigar preencher o atributo classEntity quando não estiver dentro de um @JArchColumnsDataTable 
    6. Anotações @JArchColumnDataTable para obrigar o preenchimento do atributo field
- Ajuste nas mensagens de log na geração do código
- Removido a opção de definir anotações de filtro e coluna (@JArchSearch...@JArchColumnDataTable) nos atributos
- Alteração no IBaseListTaskController para adicionar as chaves dos BPMN's pelo hook method getListProcessDefinitionKey()
- 
Acerto na página de logout para redirecionar para a página de login
- Adicionado método getProcessEngine() no IBaseListController
- Depreciado a anotação @JArchJoinFetch, utilizar a API de JPQL ou eventos em seu lugar

Correções

Além das alterações descritas acima esta versão contempla algumas correções:
- Corrigido a configuração dos filtros através das anotações dentro do package-info que estava ocasionando NullPointerException
- Correção na configuracao de colunas do @JArchColumnsDataTable
- 
Pequenas refatorações de sugestão do SonarLint
- 
Acerto na configuração do ComboBoxFieldSearchFactory para tratar quando estiver dentro de um @JArchSearchTab
- Acerto no CpfCnpjUtils para tratar NULL no formataCpf e formataCnpj

Conclusão

Essa versão contempla algumas melhorias e correções. É recomendável a atualização para essa nova versão.

Até mais,

quarta-feira, 3 de fevereiro de 2021

Versão 21.1.0-Final

 

Introdução

Nesse post vou mostrar as principais novidades da versão 21.1.0, algumas correções e pequenas alterações.

Implementações

Segue abaixo as implementações dessa versão:
- Adicionado classe RootJpql para evitar confusão nos métodos que retornavam um ClientJpql e na sequencia fosse chamado uma método que não pertencia a ela (find, searchUniqueFilter, searchAllFilter, etc...)
- Adicionado o metodo formatMMyyyy(LocalDate) no DateUtils
- Adicionado os atributos update e styleClass no filterOrder
- Adicionado os atributos update e styleClass no filterGroup
- Adicionado metodo toYearMonth(Date) no DateUtils
- Adicionado metodos list() e single() para retornar na API de JQPL para retornar uma lista de array de objetos

Alterações

Além das implementações descritas acima foram feitas algumas alterações:
- Removido os atributos depreciados clazzEntity (Utilizar classEntity), attribute (Utilizar field) e attributes (Utilizar fields)
- Removido os atributos depreciados title (Utilizar labelMenu), attributeShow (Utilizar fieldShow), attributeItems (Utilizar fieldItens) e attributeCommandJpa (Utilizar fieldCommandJpa)
- Alteração no nome dos controllers do Communication de Action para Controller (List e Data)
- Adicionado o EntityManagerFilterUtils.addFilters no construtor do ClientJpql para adicionar os filtros default's no EntityManager
- 
Adicionado o atributo classEnum no @JArchSearchFieldComboboxCommandJpa
- 
Alteração no YearMonthJpaConverter para não adicionar horário usando o Timezone
- 
Alterado a quantidade de registros no e:divListDatatable para 10, 20, 50, 100, 500 e 1000

Correções

Além das alterações descritas acima esta versão contempla algumas correções:
- Correção no BaseListTaskController para carregar os tipos de tarefas quando estiver NULL ou VAZIO
- Correção no BaseListTaskController para salvar os dados na sessão de Filtro da Task, Ordenação e Tipo
- Correção na API de JPQL para sempre adicionar o filtro de tenant (getEntityManager() adicionando filtro)
- Ajuste no metodo getValueReady() do FieldSearch para tratar o diversos formatos de Data/Hora no LocalDateTime
- Acerto no e:divListDataTable para ação dinâmica sem a tela de dados que solicita confirmação
- Ajuste no PanelSelectedUI para remover o item selecionado
- Correção na atualização do template row do componente e:divListDataTable

Conclusão

Essa versão contempla algumas melhorias e correções. É recomendável a atualização para essa nova versão.

Até mais,

segunda-feira, 11 de janeiro de 2021

Criando Estrutura de Versionamento de Scripts SQLs no Flyway

Integração FLYWAY com JARCH

 O flyway é uma excelente ferramenta para versionamento de scripts de banco de dados. Por padrão, ele utiliza a tabela schema_version para fazer o gerenciamento dos scripts executados, no entanto, podemos alterar o nome da tabela através de sua API.

Nesse post, vou usar como exemplo como criar a estrutura de versionamento de estrutura e dados, na qual deve ser gerenciada por uma tabela Flyway (TB_FLYWAYSTRUCTURE).

O primeiro passo é criar a pasta (db/migration)  dentro do resources que é por padrão onde Flyway verifica.


Após os diretórios criados, os scripts devem ser criados nessa devida pasta como demonstrado abaixo.

/db/migration/V1__script.sql


CREATE TABLE tb_empresa (
id_empresa NUMBER PRIMARY KEY,
sq_versaoregistro INTEGER DEFAULT 0 NOT NULL,
nr_cnpj VARCHAR(14) NOT NULL,
nm_fantasia VARCHAR(100) NOT NULL,
nm_razaosocial VARCHAR(100) NOT NULL,
sn_ativo BOOLEAN NOT NULL,
CONSTRAINT PK_EMPRESA PRIMARY KEY (nr_cnpj)
);

/db/migration/V2__script.sql


CREATE TABLE tb_usuario (
id_usuario NUMBER PRIMARY KEY,
sq_versaoregistro INTEGER DEFAULT 0 NOT NULL,
nm_login VARCHAR(14) NOT NULL,
cn_senha VARCHAR(255) NOT NULL,
sn_ativo CHAR(1) NOT NULL,
CONSTRAINT PK_USUARIO PRIMARY KEY (id_usuario)
);

Observação: Os scripts SQLs foram exemplificados para o banco de dados Oracle.
Finalizado a criação das tabelas, agora é possível utilizar a estrutura para fazer alterações nas tabelas do sistema, assim o V3 insere uma empresa na tabela de empresa.

/db/migration/V3__script.sql

1
INSERT INTO tb_empresa(nr_cnpj, nm_fantasia, nm_razaosocial, sn_ativo) VALUES ('03025433000190', 'Empresa', 'Empresa LTDA', true);

Criados os scripts agora é preciso configurar o Flyway para utilizar a estrutura de versionamento.

A configuração consiste em basicamente criar uma instância do flyway, passando o parâmetro locations com o path da pasta, demonstrado no trecho abaixo.


Flyway
.configure()
.cleanDisabled(true)
.dataSource(dataSourceStructure)
.schemas("ADMFIS")
.table("TB_FLYWAYSTRUCTURE")
.outOfOrder(true)
.locations("db/migration")
.load()
.migrate();

Configuração com JAVAEE e JARCH

Como estratégia de execução dos scripts utilizei o método migrate, que compara a versão atual da base dados com os scripts versionados e executa os novos arquivos inseridos na estrutura, caso queiram conhecer mais afundo sobre essa estratégia segue o link da documentação.

No Java EE a chamada das configurações de Flyway serão chamadas dentro de um método de inicialização de um EJB no Startup da aplicação.

package br.com.dsfnet.admfis.web.flyway;

import org.flywaydb.core.Flyway;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.sql.DataSource;

@Startup
@Singleton
@TransactionManagement(TransactionManagementType.BEAN)
public class FlywaySetup {

@Resource(lookup = "java:/ds/flyway")
private DataSource dataSourceStructure;

@PostConstruct
public void init() {
Flyway
.configure()
.cleanDisabled(true)
.dataSource(dataSourceStructure)
.schemas("ADMFIS")
.table("TB_FLYWAYSTRUCTURE")
.outOfOrder(true)
.locations("db/migration")
.load()
.migrate();

}
}

A classe FlywaySetup é anotada com @Startup para ser executada na inicialização da aplicação e a criação das configurações do Flyway devem ser executadas no PostConstruct para que o dataSouce esteja injetado nesse momento.

Também foi utilizada a anotação @TransactionManagement do tipo Bean porque se trata de alterações na base de dados, pois o Flyway trabalha com transações (em algumas bancos, consulte a documentação) para executar os scripts, pois, caso haja falhas na execução é precisa realizar o rollback das alterações.

Utilizei um datasource onde o usuário tem permissão de alterar estrutura do banco de dados.

Agora falta somente adicionar a dependência da API do Flyway no pom.xml:


<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>7.5.0</version>
</dependency>
Conclusão

Essa estratégia de regularização de banco de dados é uma ótima opção pois evita que um publicação seja feito em algum ambiente sem que o mesmo não tenha sido regularizado seu banco de dados. 

Até a próxima,

sábado, 2 de janeiro de 2021

Versão 20.12.0-Final

   

Introdução

Nesse post vou mostrar as principais novidades da versão 20.12.0, algumas correções e pequenas alterações.

Implementações

Segue abaixo as implementações dessa versão:
- Implementação geração de CSV assim como já tinha pra XLS e PDF na tela de lista
- Implementação geração dos dados dos detalhes no Excel
- Adicionado método getInstance() no GlobalInformation
- Adicionado os métodos single() e singleOptional() no CollectorJpql para poder retornar um Bean anêmico. Esses métodos foram incluídos com 2 versões utilizando os fields como String ou Attributte

Alterações

Além das implementações descritas acima foram feitas algumas alterações:
- Removido método getDescricaoAcao() que estava depreciado desde a versão 18.10.0
- Removido método processamentoBotaoCancelar() que estava depreciado desde a versão 18.10.0
- Removido método processamentoBotaoGravar() que estava depreciado desde a versão 18.10.0
- Removido método isMostraBotaoExcluir() que estava depreciado desde a versão 18.10.0
- Removido método isMostraBotaoGravar() que estava depreciado desde a versão 18.10.0
- Removido método isMostraBotaoVoltar() que estava depreciado desde a versão 18.10.0
- Removido método isMostraBotaoCancelar() que estava depreciado desde a versão 18.10.0
- Removido método getDescricaoBotaoGravar() que estava depreciado desde a versão 18.10.0

Correções

Além das alterações descritas acima esta versão contempla algumas correções:
- Correção no menu.xhtml para não chamar o LoginAction/LoginController indevidamente no c:if, utilizado o MenuAction e MenuController
- Correção na geração do Excel para os tipos numéricos
- Correção na geração do Excel para os tipos ENUM
- 
Correção na identificação das colunas da anotação @JArchColumnDataTable do DataDetail
- 
Correção no controle de paginação na Action de Tasks
- Correção no template principal para não sobrepor a última opção no menu

Conclusão

Essa versão contempla algumas melhorias e correções. É recomendável a atualização para essa nova versão.

Até mais,

quinta-feira, 17 de dezembro de 2020

Contas Pagar/Receber - Parte XXX - Refatoração Diversas

 Introdução

Nesse trigésimo post vou refatorar para deixar o código coeso, colocando as regras em sua devida camada. Vou atualizar também para a versão 20.12.0-SNAPSHOT.

Atualizando Versão

A primeira alteração que vou fazer é atualizar para a versão 20.12.0-SNAPSHOT.
 pom.xml:

<properties>
<jarch-version>20.12.0-SNAPSHOT</jarch-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

persistence.xml (web, job e ws)

<jar-file>lib/contas-client-1.0.0.jar</jar-file>
<jar-file>lib/jarch-core-20.12.0-SNAPSHOT.jar</jar-file>
LancamentoObserver
Agora vou mover as regras de negócio que está dentro do LancamentoObserver, movendo para métodos dentro da camada Service. A primeira alteração é mover a codificação do evento @JArchEventCreateEntity para um método dentro do Service.
LancamentoObserver:

@Inject
private LancamentoService lancamentoService;

private void criacaoLancamento(@Observes @JArchEventCreateEntity LancamentoEntity lancamento) {
lancamentoService.configuraLancamentoInclusao(lancamento);
}
LancamentoService:

@JArchParameter
@Inject
private ParametroBancoDefault parametroBancoDefault;

@JArchParameter
@Inject
private ParametroCentroCustoDefault parametroCentroCustoDefault;

@JArchParameter
@Inject
private ParametroCategoriaDefault parametroCategoriaDefault;

@JArchParameter
@Inject
private ParametroPessoaDefault parametroPessoaDefault;

@JArchParameter
@Inject
private ParametroUtilizaBpmAutorizacaoLancamento parametroUtilizaBpmAutorizacaoLancamento;


public void configuraLancamentoInclusao(LancamentoEntity lancamento) {
lancamento.setAberto(true);
lancamento.setBanco(parametroBancoDefault.getValue());
lancamento.setCentroCusto(parametroCentroCustoDefault.getValue());
lancamento.setCategoria(parametroCategoriaDefault.getValue());
lancamento.setPessoa(parametroPessoaDefault.getValue());

boolean autorizado = !parametroUtilizaBpmAutorizacaoLancamento.getValue()
|| getUserInformation().get(UsuarioEntity.class).getCargo() != CargoType.OPERADOR;

lancamento.setAutorizado(autorizado);
}

Agora vou refatorar o código que está no evento de clonagem para dentro do Service.
LancamentoObserver:

private void clonaLancamento(@Observes @JArchEventCloneEntity LancamentoEntity lancamento) {
lancamentoService.configuraLancamentoClonagem(lancamento);
}

LancamentoService:

public void configuraLancamentoClonagem(LancamentoEntity lancamento) {
lancamento.setAberto(true);

boolean autorizado = !parametroUtilizaBpmAutorizacaoLancamento.getValue()
|| getUserInformation().get(UsuarioEntity.class).getCargo() != CargoType.OPERADOR;

lancamento.setAutorizado(autorizado);
}

Agora vou refatorar o código que está no evento de validação na inclusão ou alteração para dentro do Service.
LancamentoObserver:

private void validaDataInferiorDezAnos(@Observes @JArchEventValidInsertChange         LancamentoEntity lancamento) {
lancamentoService.validaInclusaoAlteracao(lancamento);
}

LancamentoService:

public void validaInclusaoAlteracao(LancamentoEntity lancamento) {
LocalDate vencimentoMinimo = LocalDate.now().minusYears(10).withMonth(1).withDayOfMonth(1);
if (lancamento.getVencimento().isBefore(vencimentoMinimo)) {
throw new ValidationException(BundleUtils.messageBundle("message.vencimentoPartirDe",
DateUtils.formatddMMyyyy(vencimentoMinimo)));
}
}

Agora vou refatorar o código que está no evento de após a inclusão ou alteração para dentro do Service.
LancamentoObserver:

private void atualizaAlertaMensagemInclusaoAlteracao(@Observes         @JArchEventInsertChange(momentPersistMerge = MomentType.AFTER)         LancamentoEntity lancamento) {
lancamentoService.atualizaAlertaMensagemInclusaoAlteracao();
}

LancamentoService:

public void atualizaAlertaMensagemInclusaoAlteracao() {
alertaFacade.atualizaAlertaSessao();
mensagemFacade.atualizaMensagemSessao();
}

Agora vou refatorar o código que está no evento de após a exclusão ou alteração para dentro do Service.
LancamentoObserver:

private void atualizaAlertaMensagemExclusao(@Observes @JArchEventDelete(momentRemove = MomentType.AFTER)         LancamentoEntity lancamento) {
lancamentoService.atualizaAlertaMensagemExclusao();
}

LancamentoService:

public void atualizaAlertaMensagemExclusao() {
alertaFacade.atualizaAlertaSessao();
mensagemFacade.atualizaMensagemSessao();
}

Agora vou refatorar o código que está no evento de após a inclusão que está instanciando o fluxo para dentro eo Service.
LancamentoObserver:

private void instanciaFluxoLancamentoOperador(@Observes         @JArchEventInsert(momentPersist = MomentType.AFTER)
LancamentoEntity lancamento) {
lancamentoService.instanciaFluxoLancamentoOperador(lancamento);
}

LancamentoService:

public void instanciaFluxoLancamentoOperador(LancamentoEntity lancamento) {

if (getUserInformation().get(UsuarioEntity.class).getCargo() != CargoType.OPERADOR) {
return;
}

if (!parametroUtilizaBpmAutorizacaoLancamento.getValue()) {
return;
}

runtimeService
.createProcessInstanceByKey(Constant.PROCESS_AVALIACAO_CONTA)
.businessKey(lancamento.getId().toString())
.setVariable(Constant.ID_MULTITENANT, getMultiTenant().get())
.setVariable(Constant.ID_OPERADOR, getUserInformation().get().getId())
.setVariable("descricao", lancamento.getDescricao())
.setVariable("valor", lancamento.getValor().doubleValue())
.setVariable("vencimento", lancamento.getVencimento())
.execute();
}

Agora vou refatorar o código que está no evento de ação dinâmica de avaliar conta para dentro do Service.
LancamentoObserver:

private void avaliacao(@Observes @JArchEventDynamicAfter(Constant.ID_AVALIAR_LANCAMENTO)         LancamentoEntity lancamento) {
lancamentoService.avaliacao(lancamento);
}

LancamentoService:

public void avaliacao(LancamentoEntity lancamento) {
UsuarioEntity usuarioLogado = getUserInformation().get(UsuarioEntity.class);

String variavelAprovacao;

if (usuarioLogado.getCargo() == CargoType.SUPERVISOR) {
variavelAprovacao = "aprovadoSupervisor";
} else if (usuarioLogado.getCargo() == CargoType.GERENTE) {
variavelAprovacao = "aprovadoGerente";
} else {
variavelAprovacao = "aprovadoDiretor";
}

taskService.complete(lancamento.getTask().get().getId(),
Map.of(variavelAprovacao, lancamento.isAprovado(),
"valorLancamento", lancamento.getValor().doubleValue()));
}

LancamentoService

Agora vou ajustar os métodos depreciados, clientJpaql() para getClientJpql().
LancamentoObserver:

public Collection<LancamentoEntity> contaPagarAbertoAte(LocalDate vencimento) {
return getClientJpql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.equalsTo(LancamentoEntity_.autorizado, true)
.and()
.lessOrEqualsThan(LancamentoEntity_.vencimento, vencimento)
.collect()
.list();
}


public Collection<LancamentoEntity> contaPagarAbertoEm(LocalDate vencimento) {
return getClientJpql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.equalsTo(LancamentoEntity_.autorizado, true)
.and()
.equalsTo(LancamentoEntity_.vencimento, vencimento)
.collect()
.list();
}

Agora vou ajustar o método depreciado, find() para getClientJpql().find().
LancamentoService:

public void autorizaConta(Long idLancamento) {
LancamentoEntity lancamento = getClientJpql().find(idLancamento);
lancamento.setAutorizado(true);
change(lancamento);
}

Métodos Depreciados 

Agora vou ajustar os métodos depreciados:
De clientJpaql() para getClientJpql()
De count() para getClientJpql().count()
De searchUniqueFilter() para getClientJpql().searchUniqueFilter()
De ICrudListAction para ICrudListController

SonarLint
Agora vou chamar o SonarLint para verificar as sugestões de melhorias no LancamentoService. 

1. A primeira sugestões que ele propôs foi que existem dois métodos duplicados, sugerindo deixar somente um. Então vou renomear o método atualizaAlertaMensagemExclusao() para atualizaAlertaMensagem() e vou excluir o atualizaAlertaMensagemInclusaoAlteracao().

2. Agora ele está sugerindo que isPresent() em um Optional para acessar o valor.

lancamento
.getTask()
.ifPresent(t -> taskService.complete(t.getId(),
Map.of(variavelAprovacao, lancamento.isAprovado(),
"valorLancamento", lancamento.getValor().doubleValue())));
3. Agora está sugerindo para utilizar o Boolean.TRUE.

if (!Boolean.TRUE.equals(parametroUtilizaBpmAutorizacaoLancamento.getValue())) {
return;
}

4. Agora está sugerindo para utilizar o try resources. 

public StreamedContent downloadComprovanteBaixa(LancamentoEntity lancamento) {
Document document = new Document();
try {
File file = File.createTempFile("comprovante", ".pdf");
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
PdfWriter.getInstance(document, fileOutputStream);
document.open();
document.add(new Paragraph("Comprovante de Pagamento Conta " + lancamento.getTipoLancamento().getDescription()));
document.add(new Paragraph("Codigo......: " + lancamento.getCodigo()));
document.add(new Paragraph("Descrição...: " + lancamento.getDescricao()));
document.add(new Paragraph("Banco.......: " + lancamento.getBanco().getCodigo() + " - " + lancamento.getBanco().getNome()));
document.add(new Paragraph("Centro Custo: " + lancamento.getCentroCusto().getCodigo() + " - " + lancamento.getCentroCusto().getDescricao()));
document.add(new Paragraph("Categoria...: " + lancamento.getCategoria().getCodigo() + " - " + lancamento.getCategoria().getDescricao()));
document.add(new Paragraph("Pessoa......: " + CpfCnpjUtils.formataCpfCnpj(lancamento.getPessoa().getCpfCnpj()) + " - " + lancamento.getPessoa().getNome()));
document.add(new Paragraph("Vencimento..: " + DateUtils.formatddMMyyyy(lancamento.getVencimento())));
document.add(new Paragraph("Valor.......: " + NumberUtils.formatMoney(lancamento.getValor())));
document.add(new Paragraph("Código de autenticação: " + Md5Utils.generate(NumberUtils.formatZeroLeft(lancamento.getId(), 10))));
document.close();
return new DefaultStreamedContent(new FileInputStream(file), FileType.PDF.getContentType(), "comprovante.pdf");
}
} catch (DocumentException | IOException ioe) {
throw new ValidationException("Erro na geração do comprovante...");
} finally {
document.close();
}
}

5. E por último está pedindo para acertar a chamada do código depreciado new DefaultStreamedContent.

try (FileInputStream fileInputStream = new FileInputStream(file)) {
return DefaultStreamedContent
.builder()
.stream(() -> fileInputStream)
.contentEncoding(FileType.PDF.getContentType())
.name("comprovante.pdf")
.build();
}
Referência Circular
Com as refatorações anteriores causei um problema de referência circular do CDI. Agora minha classe LancamentoService faz uma injeção ao AlertaFacade e o MensagemFacade, e por sua vez tanto o AlertaFacade quando o MensagemFacade faz uma injeção ao LancamentoService. Para resolver isso vou mover os métodos do AlertaFacade e MensagemFacade para o LancamentoService, vou excluir as classes AlertaFacade e o MensagemFacade e ajustar os pontos na aplicação que faziam referência as essas classes para utilizar o LancamentoService.
LancamentoService.java:

public class ComunicacaoObserver {

@Inject
private LancamentoService lancamentoService;

private void inclusaoAlteracao(@Observes @JArchEventInsertChange(momentPersistMerge = MomentType.AFTER) CommunicationEntity communicationEntity) {
lancamentoService.atualizaAlertaMensagem();
}

private void exclusao(@Observes @JArchEventDelete(momentRemove = MomentType.AFTER) CommunicationEntity communicationEntity) {
lancamentoService.atualizaAlertaMensagem();
}
}
ComunicacaoObserver.java:

public class ComunicacaoObserver {

@Inject
private LancamentoService lancamentoService;

private void inclusaoAlteracao(@Observes @JArchEventInsertChange(momentPersistMerge = MomentType.AFTER) CommunicationEntity communicationEntity) {
lancamentoService.atualizaAlertaMensagem();
}

private void exclusao(@Observes @JArchEventDelete(momentRemove = MomentType.AFTER) CommunicationEntity communicationEntity) {
lancamentoService.atualizaAlertaMensagem();
}
}
LoginObserver.java:

public class LoginObserver {

private void login(@Observes @JArchEventLoginAfter UsuarioEntity usuario, LancamentoService lancamentoService) {
lancamentoService.atualizaAlertaMensagem();

if (usuario.getCargo().equals(CargoType.DIRETOR) || usuario.getCargo().equals(CargoType.GERENTE)) {
JsfUtils.getSession().setMaxInactiveInterval(600);
}
}
}
SessionListener.java:

@WebListener
public class SessionListener implements HttpSessionListener {

@Inject
private TenantService tenantFacade;

@Inject
private LancamentoService lancamentoService;

@Inject
private UsuarioService usuarioFacade;

@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
tenantFacade.configTenant(JsfUtils.getServerName());
usuarioFacade.criaUsuarioAdmin();
lancamentoService.atualizaAlertaMensagem();
}

@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
LogUtils.warning("SESSION TIMEOUT !!!");
}
}
Conclusão
Nesse post fiz a atualização do projeto para a versão mais atual do JARCH (na publicação desse Post), e algumas melhorias no código. Melhorias no código devem ser frequentemente aplicadas, principamente quando o código sofre constantes alterações ou implementações. Uma boa prática de programação é sempre manter o código mais simples possível, ser auto documentado, utilização de boas práticas de programação orientada a objetos, buscando sempre a coesão e desacoplamento.

Até mais,

Versão 23.3.0-Final

      Introdução Nesse post vou mostrar as principais novidades da versão 23.3.0, algumas correções e pequenas alterações. Alterações Além d...