quarta-feira, 5 de dezembro de 2018

Versão 18.11.0 Final

Introdução

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

Implementações

- Adicionado um hook metodo beforeFillDataModeList() para interceptação da consulta nas actions de List e FilterSelect.

- Adicionado um listener JPA para remover as máscaras antes da persistência no banco de dados.

- Alterado o APT para gerar os artefatos que eram gerados somente em tempo de compilação na pasta source do projeto. 

Criado a classe CSS jarch-panelgrid para ser usado com o h:panelGrid, essa classe possuí a mesma configuração de margim do a:panelGrid.

- Remoção de alguns métodos depreciados.

- Criado uma nova anotação para atributos de auto-incremento, evitando o uso desnecessario de objetos específicos do banco de dados (Ex: SEQUENCE). A anotação é @JArchAutoIncrement.

- Adicionado os metodos hasMessageWarn(), hasMessageInfo(), hasMessageError() e hasMessageFatal() no JsfUtils.

- Adicionado atributos showButtomCancel e showButtomReturn no e:divDataMaster.

- Adicionado o agrupamento e ordenação no relatório da tela de lista.

- Adicionado novo composite component e:inputAddress e alterado geração do código para contemplar esse novo tipo.

- Adicionado novo método para geração do dígito verificado para Módulo 10 Modulo10.calculaDigitoVerificador()

Correções

Além das implementações descritas acima versão contempla:

- Correção na clonagem do registro quando houver um atributo com anotação @Embeddable

- Tradução de métodos para a lingua inglesa

- Acerto na geração do XHTML para o atributo required dos DataDetails (Não utilizar mais o método,  usar o literal true)

- Correção na anotação @ArchColumnDatatable para saber adicionar no grid do detail mesmo quando a entidade nao estiver no mesmo pacote da entidade principal

ROADMAP

O próxima versão do JARCH contemplará o JAVA 11

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, 31 de outubro de 2018

Versão 18.10.0 Final

Introdução

Nesse post vou mostrar as principais novidades da versão 18.10.0, sendo que o carro chefe dessa versão é o desmebramento do jarch-framework em alguns módulos e algumas correções e pequenas alterações.

Desmembramento JARCH-FRAMEWORK

Vou começar mostrando os novos módulos.

jarch-framework

Esse módulo foi renomeado para jarch-crud

jarch-cep

Esse módulo contempla um serviço parap busca de CEP

jarch-jsf

Esse módulo contempla algumas classes relacionadas ao JSF e os composites componentes

jarch-jpa

Esse módulo contempla algumas classes relacionadas ao JPA

Demais Implementações e Correções

Além da criação dos módulos acima essa versão contempla:

- Correção na validação do email que criticava como um email inválido quando iniciava com números

- Remoção do beans.xml porque estava configurado para subir todas as classes elegíveis para o contexto do CDI

- Correção nos limites de transação JPA

- Alterado o modo de uso do @Repetable para usar um interface local dentro das anotações, evitando a criação de um mesmo arquivo com um "s" no final

- Ajustes nos listener para usar injeção via CDI

- Removido o autoApply = true dos conversores JPA de LocalDate, LocalDatTime e LocalTime porque a JPA 2.2 (JAVAEE 8) ja contempla a conversão desses tipos

- Correção na mensagem de erro padrão do @ArchValidRequiredOneOfManyField

- Ajustes nos filtros de condições para não mostrar os tipo MEMBER_OF, NOT_MEMBER_OF, EMPTY e NOT_EMPTY

- Ajustes nos pacotes de alguns módulos

- Acerto no DataDetail para não propagar o erro para a próxima ação de CRUD e também não permitir acionar uma ação de CRUD quando estiver no modo de edição

- Ajuste no BpmUtils.claim() que não estava gravando o usuário que assumiu a tarefa

- Alteração no CrudDataAction para permitir continuar no modo de edição após a gravação

- Removido as anotações @ArchEventManagerBeforeConsult e @ArchEventManagerAfterConsult que não era usado

ROADMAP

O próxima versão do JARCH contemplará o JAVA 11

Conclusão

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

Até mais,

sexta-feira, 5 de outubro de 2018

Versão 18.9.0 - Final

Introdução

Nesse post vou mostrar as principais novidades da versão 18.9.0, sendo que o carro chefe dessa versão é o desmebramento do jarch-framework em alguns módulos e o binário sendo criado com JAVA 10.

Desmembramento JARCH-FRAMEWORK

Vou começar mostrando os novos módulos.

jarch-annotation

Esse módulo basicamente estão a maioria das anotações do JARCH, desde anotações de eventos, extensões Bean Validation, etc.

jarch-apt

Esse módulo contempla as classes que implementam os Annotation Processors, que é a geração de classes no momento da compilação, além de algumas dezenas de validações do código

jarch-bpm

Esse módulo encapsula as chamadas da API REST do BPM (implementação do Camunda)

jarch-docx

Esse módulo possue uma implementação para uma biblioteca de merge de documentos no formato Word e Excel

jarch-exception

Esse módulo contempla as classes de exceções

jarch-jdbc

Esse módulo contempla uma biblioteca para chamadas via JDBC

jarch-migration

Esse módulo contempla uma biblioteca para migração de dados entre Tenants

jarch-model

Esse módulo contempla as classes de modelo

jarch-report

Esse módulo contempla a biblioteca para geração de relatórios no formato JasperReports

jarch-svn

Esse módulo possue uma biblioteca para acesso ao SVN

jarch-test

Esse módulo contempla uma biblioteca para geração de testes

jarch-utils

Esse módulo contempla varias classes utilitárias

Demais Implementações e Correções

Além da criação dos módulos acima essa versão contempla:

- Remoção anotações, @ArchLoadCrud, @ArchMenuActionExtra, @ArchMenuActionSelected, @ArchMenuDownloadExtra e @ArchMenuReportExtra

- Conversão dos metodos para lingua inglesa nas classes de exceções

- Adicionado atributos de confirmação nas anotações @ArchDynamicShowDataAction e @ArchDynamicDirectAction

- Adicionado novo evento de validacao de ação dinâmica @ArchEventValidDynamic

- Renomeado as anotações 
  @ArchEventLoadCrudDataInsert para @ArchEventLoadInsert 
  @ArchEventLoadCrudDataChange para @ArchEventLoadChange 
  @ArchEventLoadCrudDataClone para @ArchEventLoadClone 
  @ArchEventLoadCrudDataConsult para @ArchEventLoadConsult
  @ArchEventLoadCrudDataDelete para @ArchEventLoadDelete

- Implementação na biblioteca de teste para salvar a tela (printscreen) na ocorrência de erro

- Correção na verificação de exclusão (relacionamentos)

- Correção na mostragem de erro para não mostrar mensagens duplicadas

- Adicionado novas funcionalidades na biblioteca de JPQL, distinct(), set(), groupByList() e groupBySet()

- Adicionado hooks métodos para personalizar o título e mensagem de concluído com sucesso

- @ArchValidExclusives agora contempla o @Repeatable (permite mais de uma anotação na classe)

- Alterado o nome do modulo jarch-bom para jarch, vide exemplo abaixo linha 5.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>br.com.jarch</groupId>
                <artifactId>jarch</artifactId>
                <version>18.9.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

JAVA 10

O JAVA 10 foi lançado em Março/2018, e a versão atual é compilada com JAVA 10. As versões anteriores eram compiladas com o JAVA 8.

ROADMAP
O próxima versão do JARCH contemplará o JAVAEE 8.

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, 25 de setembro de 2018

Migração de dados

Introdução

Nesse post veremos como migrar dados de um banco de dados para outro via aplicação.

Migração

No Jarch já é nativo a página e a lógica para efetuar essa migração, basta adicionar no menu conforme abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@JArchViewScoped
public class MenuAction extends BaseMenuAction {

    @Override
    public List<IMenu> createMenu() {
        List<IMenu> menu = new ArrayList<>();

        menu.add(MenuBuilder
                .newInstance()
                .name("Migração")
                .action("../migration/migration.jsf")
                .build());

        return menu;
    }
}

Irá aparece a tela abaixo:

Todas as entidades que implementarem a interface ICrudEntity serão filtradas para mostrar na caixa de seleção, e estarão disponíveis para a migração, com exceção das classes que estiverem com a anotação @ArchIgnoreMigrate.

Conforme um item é selecionado, é feito uma busca no banco de dados para possível filtro, caso nenhum registro seja selecionado todos os dados da tabela serão migrados:


Para uma melhor visualização dos dados será necessário sobre escrever o método toString() conforme abaixo:
1
2
3
4
5
 @Override
 public String toString() {
  return BundleUtils.messageBundle("label.codigo") + ": " + codigo +
    BundleUtils.messageBundle("label.descricao") + ": " + descricao;
 }

Conforme é escolhido a(s) entidade(s) a ser migrada é gerado um arquivo "migracao.zip" contendo os objetos serializados separados por pastas:

Restauração

Na mesma página existe outra aba logo acima para fazer a restauração dos dados que anteriormente foram filtrados, conforme os passos acima.

Na aba de restauração é semelhante a aba de migração onde as entidades disponíveis serão filtradas e estarão disponíveis para a restauração, e o arquivo para fazer o upload.



Conclusão

Nesse post vimos como deixar disponível a página de migração no menu, como configurar as entidades para filtro e as que não devem estar disponíveis, como deixar os dados mais apresentáveis e como restaurar os dados.

Até mais,

quarta-feira, 12 de setembro de 2018

API de Relatório

Introdução

Nesse post vou mostrar como criar relatórios simples, dinâmicos, com agrupamentos e subrelatórios.

ReportBuilder

Para a utilização da API de relatórios temos a classe ReportBuilder que através de sua interface fluente facilita a construção do relatório, segue abaixo um exemplo de um relatório simples:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public StreamedContent relatorioSimples() {
        List<ProdutoEntity> listaProduto = criaListaProduto();

        ReportBuilder reportBuilder = ReportBuilder
                .createInstance()
                .setTitle("Relatório de Produtos")
                .setSubtitle("Período: 01/2017 até 12/2017")
                .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class)
                .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class)
                .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class)
                .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false)
                .withListData(listaProduto);

        try {
            return reportBuilder.exportPdf("relatorioProdutoSimples");
        } catch (JRException | IOException ex) {
            LogUtils.generate(ex);
        }

        return null;
    }

    private List<ProdutoEntity> criaListaProduto() {
        List<ProdutoEntity> listaProduto = new ArrayList<>();
        listaProduto.add(criaProduto("001", "Caneta", UnidadeType.UNIDADE, "1.39"));
        listaProduto.add(criaProduto("002", "Borracha", UnidadeType.UNIDADE, "3.27"));
        listaProduto.add(criaProduto("003", "Mouse", UnidadeType.UNIDADE, "10.50"));
        listaProduto.add(criaProduto("004", "Teclado", UnidadeType.UNIDADE, "45.60"));
        listaProduto.add(criaProduto("005", "Monitor", UnidadeType.UNIDADE, "109.99"));

        return listaProduto;
    }

    private ProdutoEntity criaProduto(String codigo, String descricao, TipoType tipo, String valor){
        ProdutoEntity produtoEntity = new ProdutoEntity();
        produtoEntity.setCodigo(codigo);
        produtoEntity.setDescricao(descricao);
        produtoEntity.setTipo(tipo);
        produtoEntity.setValor(new BigDecimal(valor));

        return produtoEntity;
    }

Na linha 2 criamos uma lista simples para a saída do relatório. A partir da linha 4 começa a construção, segue um exemplo da saída acima:

Estilizando o cabeçalho da página com um template:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public StreamedContent relatorioComTemplate() {
        List<ProdutoEntity> listaProduto = criaListaProduto();

        ReportBuilder reportBuilder = ReportBuilder
                .createInstance()
                .setTitle("Relatório de Produtos")
                .setSubtitle("Período: 01/2017 até 12/2017")
                .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class)
                .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class)
                .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class)
                .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false)
                .withListData(listaProduto)
                .addParameter("emissor", "Bruno Araujo")
                .addParameter("sistema", BundleUtils.messageBundle("label.siglaSistema"))
                .addParameter("tituloPrefeitura", BundleUtils.messageBundle("label.titulo1"))
                .addParameter("tituloSecretaria", BundleUtils.messageBundle("label.titulo2"))
                .addParameter("imagemTopo",JsfUtils.getPath("resources/images/logo-menu.png"))
                .setTemplateFile(JsfUtils.getPath("relatorios/templates/") + "templateReportLandscape.jrxml")
                .withLandscapeOrientation();

        try {
            return reportBuilder.exportPdf("relatorioProdutoSimples");
        } catch (JRException | IOException ex) {
            LogUtils.generate(ex);
        }

        return null;
    }

Saída:

ReportGroupBuilder

Para criar agrupamento no relatório utilizamos em conjunto com o ReportBuilder a classe ReportGroupBuilder conforme abaixo:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public StreamedContent relatorioComGrupo() {
        List<ProdutoEntity> listaProduto = criaListaProduto();

        ReportBuilder reportBuilder = ReportBuilder
                .createInstance()
                .setTitle("Relatório de Produtos")
                .setSubtitle("Período: 01/2017 até 12/2017")
                .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class)
                .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class)
                .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class)
                .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false)
                .withListData(listaProduto);

        try {
            return reportBuilder
                    .addGroup(ReportGroupBuilder.createInstance(reportBuilder, "tipo")
                            .addFooterVariable("SubTotal","codigo", DJCalculation.COUNT)
                            .addFooterVariable("valor", DJCalculation.SUM)
                            .build())
                    .addGrandTotalLegend(BundleUtils.messageBundle("label.total"))
                    .addGlobalFooterVariable("valor", DJCalculation.SUM)
                    .exportPdf("relatorioProdutoGrupo");
        } catch (JRException | IOException e) {
            LogUtils.generate();
        }

        return null;
    }

Na linha 15 criamos um agrupamento para o atributo tipo da classe que esta na lista, conforme o valor desse atributo muda é gerado um totalizador no atributo valor e um totalizador geral, conforme abaixo.

Obs: para o agrupamento funcionar conforme o esperado a lista deve estar ordenada conforme a necessidade:


Com um agrupamento mais elaborado:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public StreamedContent relatorioComGrupoHeaderEFooter() {
        List<ProdutoEntity> listaProduto = criaListaProduto();

        ReportBuilder reportBuilder = ReportBuilder
                .createInstance()
                .setTitle("Relatório de Produtos")
                .setSubtitle("Período: 01/2017 até 12/2017")
                .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class)
                .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class)
                .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class)
                .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false)
                .withListData(listaProduto);

        try {
            return reportBuilder
                    .addGroup(ReportGroupBuilder.createInstance(reportBuilder, "tipo")
                            .setGroupLayout(GroupLayout.VALUE_FOR_EACH)
                            .addHeaderVariable("tipo", DJCalculation.FIRST)
                            .addFooterVariable("SubTotal","codigo", DJCalculation.SYSTEM)
                            .addFooterVariable("descricao", DJCalculation.COUNT)
                            .addFooterVariable("valor", DJCalculation.SUM)
                            .build())
                    .addGrandTotalLegend(BundleUtils.messageBundle("label.total"))
                    .addGlobalFooterVariable("descricao", DJCalculation.COUNT)
                    .addGlobalFooterVariable("tipo", DJCalculation.SYSTEM)
                    .addGlobalFooterVariable("valor", DJCalculation.SUM)
                    .exportPdf("relatorioProdutoGrupo");
        } catch (JRException | IOException e) {
            LogUtils.generate();
        }

        return null;
    }

Saída:

ReportSubReportBuilder

Com um subrelatório é possível colocar uma lista no meio do detalhe do relatório, usaremos em conjunto com o ReportBuilder e ReportGroupBuilder, conforme abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public StreamedContent relatorioComSubRelatorio() {
        List<ProdutoEntity> listaProduto = criaListaProduto();

        ReportBuilder reportBuilder = ReportBuilder
                .createInstance()
                .setTitle("Relatório de Produtos")
                .setSubtitle("Período: 01/2017 até 12/2017")
                .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class)
                .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class)
                .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class)
                .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false)
                .addField("listaMateriaPrima", List.class)
                .withListData(listaProduto);

        try {
            return reportBuilder
                    .addGroup(ReportGroupBuilder.createInstance(reportBuilder, "codigo").build())
                    .addSubReport(ReportSubReportBuilder
                            .createInstance()
                            .addField(BundleUtils.messageBundle("label.nome"), "nome", 300, String.class)
                            .addField(BundleUtils.messageBundle("label.quantidade"), "quantidade", 200, Long.class)
                            .build(),
                            "listaMateriaPrima",
                            1)
                    .exportPdf("relatorioProdutoSubRelatorio");
        } catch (JRException | IOException ex) {
            LogUtils.generate(ex);
        }

        return null;
    }

Saída:

Conclusão

Nesse post mostrei alguns exemplos de como implementar relatórios de forma dinâmica (Relatório simples, com template, com agrupamento e/ou subrelatório), sem muita complexidade na criação e manutenção.

Até mais,

terça-feira, 11 de setembro de 2018

Eventos - Parte 5/5

Introdução

Nesse post vou mostrar algumas maneiras de interceptar os ações nas Actions (lista e dados). Não são necessariamente eventos, são implementações de métodos informando via anotação o momento que serão chamados, causando o mesmo efeito de um evento.

Vamos começar pelo action de lista, uma vez que a action de lista que faz a chamada a tela de dados.

@JArchCrudListBeforeCallInsert

Essa anotação deve ser usada em um método da action de lista. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento que for clicado no botão incluir da tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@JArchViewScoped
public class ListaBancoAction extends CrudListAction<BancoEntity, BancoFacade> {

 @Inject
 private UserInformation userInformation;

 @Override
 public String getPageData() {
  return "dadosBanco.jsf";
 }

 @JArchCrudListBeforeCallInsert
 public void antesInclusao() {
  if (!userInformation.get(UsuarioEntity.class).isMaster()) {
   throw new ValidationException(BundleUtils.messageBundle("message.permissaoNegadaParaEssePerfil"));
  }
 }
}

Observe que a assinatura desse método não recebe nenhum parâmetro. Desse tipo de evento somente esse método não recebe a entidade por parâmetro.

@JArchCrudListBeforeCallChange

Essa anotação deve ser usada em um método da action de lista. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento que for clicado no botão alterar da tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@JArchViewScoped
public class ListaBancoAction extends CrudListAction<BancoEntity, BancoFacade> {

 @Inject
 private UserInformation userInformation;

 @Override
 public String getPageData() {
  return "dadosBanco.jsf";
 }

 @JArchCrudListBeforeCallChange
 public void antesAlteracao(BancoEntity banco) {
  if (!userInformation.get(UsuarioEntity.class).isMaster()) {
   throw new ValidationException(BundleUtils.messageBundle("message.permissaoNegadaParaEssePerfil"));
  }
 }
}

Observe que a assinatura desse método recebe a entidade por parâmetro. Com exceção do @ArchCrudListBeforeCallInsert todos os demais recebem ese mesmo parâmetro.

@JArchCrudListBeforeCallClone

Essa anotação deve ser usada em um método da action de lista. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento que for clicado no botão clonar da tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@JArchViewScoped
public class ListaBancoAction extends CrudListAction<BancoEntity, BancoFacade> {

 @Inject
 private UserInformation userInformation;

 @Override
 public String getPageData(BancoEntity banco) {
  return "dadosBanco.jsf";
 }

 @JArchCrudListBeforeCallClone
 public void antesClonagem() {
  if (!userInformation.get(UsuarioEntity.class).isMaster()) {
   throw new ValidationException(BundleUtils.messageBundle("message.permissaoNegadaParaEssePerfil"));
  }
 }
}

@JArchCrudListBeforeCallConsult

Essa anotação deve ser usada em um método da action de lista. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento que for clicado no botão consultar da tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@JArchViewScoped
public class ListaBancoAction extends CrudListAction<BancoEntity, BancoFacade> {

 @Inject
 private UserInformation userInformation;

 @Override
 public String getPageData() {
  return "dadosBanco.jsf";
 }

 @JArchCrudListBeforeCallConsult
 public void antesConsultar(BancoEntity banco) {
  if (!userInformation.get(UsuarioEntity.class).isMaster()) {
   throw new ValidationException(BundleUtils.messageBundle("message.permissaoNegadaParaEssePerfil"));
  }
 }
}

@JArchCrudListBeforeCallDelete

Essa anotação deve ser usada em um método da action de lista. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento que for clicado no botão excluir da tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@JArchViewScoped
public class ListaBancoAction extends CrudListAction<BancoEntity, BancoFacade> {

 @Inject
 private UserInformation userInformation;

 @Override
 public String getPageData() {
  return "dadosBanco.jsf";
 }

 @JArchCrudListBeforeCallDelete
 public void antesExcluir(BancoEntity banco) {
  if (!userInformation.get(UsuarioEntity.class).isMaster()) {
   throw new ValidationException(BundleUtils.messageBundle("message.permissaoNegadaParaEssePerfil"));
  }
 }
}

Agora veremos os eventos que podem ser implementados na action de dados.

@JArchCrudDataStartEnviromentInsert

Essa anotação deve ser usada em um método da action de dados. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento da abertura da tela de dados. Ele é disparado quando acionado a ação de incluir na tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@JArchViewScoped
public class DadosBancoAction extends CrudDataAction<BancoEntity, BancoFacade> {

 @Override
 public String getPageList() {
  return "listaBanco.jsf";
 }

 @JArchCrudDataStartEnviromentInsert
 public void iniciaModoInclusao() {
  getEntity().setCodigo("XXX");
  getEntity().setCodigo("Entre com o nome do banco");
 }
}

@JArchCrudDataStartEnviromentClone

Essa anotação deve ser usada em um método da action de dados. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento da abertura da tela de dados. Ele é disparado quando acionado a ação de clonar na tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@JArchViewScoped
public class DadosBancoAction extends CrudDataAction<BancoEntity, BancoFacade> {

 @Override
 public String getPageList() {
  return "listaBanco.jsf";
 }

 @JArchCrudDataStartEnviromentClone
 public void iniciaModoClonagem() {
  getEntity().setCodigo("CLONE");
  getEntity().setNome("Nome do banco clonado");
 }
}

@JArchCrudDataStartEnviromentChange

Essa anotação deve ser usada em um método da action de dados. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento da abertura da tela de dados. Ele é disparado quando acionado a ação de alterar na tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@ArchViewScoped
public class DadosBancoAction extends CrudDataAction<BancoEntity, BancoFacade> {

 @Override
 public String getPageList() {
  return "listaBanco.jsf";
 }

 @JArchCrudDataStartEnviromentChange
 public void iniciaModoAlteracao() {
  // Carregar componentes visuais para visualização  
 }
}

@JArchCrudDataStartEnviromentConsult

Essa anotação deve ser usada em um método da action de dados. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento da abertura da tela de dados. Ele é disparado quando acionado a ação de consultar na tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@JArchViewScoped
public class DadosBancoAction extends CrudDataAction<BancoEntity, BancoFacade> {

 @Override
 public String getPageList() {
  return "listaBanco.jsf";
 }

 @JArchCrudDataStartEnviromentConsult
 public void iniciaModoConsulta() {
  // Carregar componentes visuais para visualização
 }
}

@JArchCrudDataStartEnviromentDelete

Essa anotação deve ser usada em um método da action de dados. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento da abertura da tela de dados. Ele é disparado quando acionado a ação de excluir na tela de lista.
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@JArchViewScoped
public class DadosBancoAction extends CrudDataAction<BancoEntity, BancoFacade> {

 @Override
 public String getPageList() {
  return "listaBanco.jsf";
 }

 @JArchCrudDataStartEnviromentDelete
 public void iniciaModoExclusao() {
  // Carregar componentes visuais para visualização
 }
}

Existe mais dois eventos que podem ser interceptados, mas que são em um outro momento dentro da tela dados.

@JArchCrudDataBeforeSave

Essa anotação deve ser usada em um método da action de dados. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento do click de confirmação na tela de dados mas antes de efetivar a gravação dos dados. 
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@JArchViewScoped
public class DadosBancoAction extends CrudDataAction<BancoEntity, BancoFacade> {

 @Override
 public String getPageList() {
  return "listaBanco.jsf";
 }

 @JArchCrudDataBeforeSave
 public void antesSalvar() {
  // Ajusta dados conforme seleção dos componentes visuais
 }
}

@JArchCrudDataAfterSave

Essa anotação deve ser usada em um método da action de dados. Essa anotação é uma variação da implementação do design pattern Template Method, só que com a flexibilidade de definir o nome método. Esse método anotado passa a ser um Hook Méthod e é chamado no momento do click de confirmação na tela de dados mas após a efetivar a gravação dos dados. 
Segue um exemplo abaixo:
1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@JArchViewScoped
public class DadosBancoAction extends CrudDataAction<BancoEntity, BancoFacade> {

 @Override
 public String getPageList() {
  return "listaBanco.jsf";
 }

 @ArchCrudDataAfterSave
 public void depoisSalvar() {
  // Ajusta dados conforme seleção dos componentes visuais
 }
}

Conclusão

Finalizamos os posts relacionados a eventos, conforme visto nos posts anteriores existem diversos tipos de eventos no framework. Esses eventos são de grande importância para manter o código com baixo acoplamento e coeso.

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...