EventDispatcher

De BIS Wiki
Ir para navegação Ir para pesquisar

O EventDispatcher é o serviço do BIS utilizado para notificar outras partes do sistema quando detemrinados eventos ocorrem de forma "automática". Por exemplo:

  • Evento de Persistência/Exclusão de um Objeto
  • Evento de Email Recebido
  • Evento de Falha de Conexão
  • Etc.


Funcionamento

Disparo do Evento

Na parte do código em que o evento ocorre, implementamos apenas a chamada do EventDispatcher passando o Identificador do Evento e as propriedades do evento. Deixando o código neste ponto "limpo", pois temos apenas uma linha que sinaliza o disparo do evento.

Exemplo de disparo de evento de "chegada de e-mail":

EventDispatcher.fire(BISSystem.EVENT_MAIL_FETCH, params);


Registro do Listener

O registro do listener é a ação de inscrever alguma parte do sistema para receber a notificação toda vez que o evento ocorrer. Conhecido no Java como registrar o Listener. O registro dos Listener deve ser feito diretamente na classe do Brainz, para que seja feito logo assim que o sistema inicializar.

Note 64.png
Implementação do Listener no Package Correto!
Embora a inscrição do listener no EventDispatcher seja feito no Brainz, a implementação do listener deve ser feita como uma classe completa dentro do package do módulo/service que ouvirá o registro. JAMAIS o listener deve ser uma inner-class dentro do Brainz.


Regras de Funcionamento

  • Toda vez que um evento for disparado, o EventDispatcher guarda as informações passadas no disparo do evento e cria uma nova Thread para realizar as notificações dos listeners.
  • Por ser disparada em uma nova Thread dentro do EventDispatcher temos as seguintes condições:
    • O método de disparo de evento nunca gera erro para a classe que disparou o evento. Logo o EventDispatcher não "trava" nem segura a execução da Thread onde o evento ocorreu.
    • A execução dos listeners podem ocorrer em paralelo. Logo é bom chamar o listener quando a Thread estiver pronta para terminar ou as alterações da Thread (como cadastros no banco de dados) podem não estar consistentes para as classes de listeners, já que a thread do evento ainda não foi confirmada (deu commit).
    • Erros na execução dos listeners (lançamento de Exceptions) não atrapalha o funcionamento nem causará RollBack na thread principal que gerou o evento. Deixando ela totalmente destacada.
    • A chamada ocorrerá fora de qualquer sessão, tanto do BISSession quando de Transaction do CMT. Qualquer chamada à fachada precisará de autenticação e de criação de uma sessão.


Stop 256.png
Listeners Totalmente Independentes
Se um listener deixe escapar uma Exception (mesmo que uma RunTimeException), esta será registrada como um Erro crítico e o próximo Listener será chamado. Todos os listeners serão notificados e mesmo que um termine em exception, não causará RollBack em outros, muito menos impedirá que outros listeners recebam sua notificação.


Note 64.png
Registro dos IDs de Eventos
Para centralizar os Identificadores dos Eventos, todos os IDs de eventos do BIS devem ser registrados como constantes na classe BISSystem com o prefixo "EVENT_".

Vantagens Do EventDispatcher

As principais vantagens do EventDispatcher são:

  • deixa o código mais limpo ao evitar que tenhamos chamadas de métodos de uma parte de código diretamente para outros módulos/serviços diferentes.
  • destaca as transações entre partes do código ao iniciar os listeners em threads separadas temos eles totalmente independentes e impedindo que uma parte do código que eventualmente tenha erro atrapalhe o funcionamento de outra.


Eventos Atuais e Suas Propriedades

ID do Evento Propriedade Conteúdo
EVENT_MAIL_FETCH

companyID

ID da Empresa que Recebeu o E-mail

mailboxID

ID da Caixa de E-mail que foi verificada para receber esse e-mail.

messages

Lista de MailMessageVO representando todas as mensagens que foram recebidas.


Before BISV10

O framework disponibiliza um serviço de 'Event Dispatcher' (Despachador de Eventos) que tem a finalidade de centralizar a notificação dos listeners quando um evento ocorrer. Um dispatcher centralizado trás as seguintes vantagens:

  • quando um módulo tem um evento para ser disparado este só precisa notificar o event dispatcher que tal evento ocorreu, e não precisa implementar classes para que os listeners se registrem e gerênciar o disparo para cada um.
  • um listener pode se inscrever para receber notificações de um evento, sem ter que se preocupar se o módulo que gera este evento está atualmente instalado ou não, já que o dispatcher gerenciará isso.
  • o dispatcher manterá os eventos de forma padronizada e coerente entre todos os módulos.


Note 64.png
Eventos de Negócio
Note que o Event Dispatcher é uma solução para disparo e tratamento de eventos para a camada de negócio! Eventos da camada de apresentação são pertinentes a sessão do usuário e devem ser tratadas na camada de apresentação! Mesmo que as ações do usuário na camada de apresentação (ou mesmo de integração) possam disparar eventos na camada de negócio através do Event Dispatcher.


Funcionamento

O dispatcher funciona pelo pattern singleton. Sendo único e sendo iniciado pela primeira classe que recuperar sua instância, seja para notificar um evento ou seja para se inscrever para notificações.


Note 64.png
Arquitetura e Futuro
O EventDispacher foi projetado para que no futuro ele possa notificar eventos de diversas formas, como por chamada de EJB, JMS, e-mail, etc. A principio a única implementação feita será a chamada através de listeners registrados no singleton. Como o BISERP não tem previsão para ser distribuido em JVMs diferentes, o Singleton oferece todo o suporte necessário sem maiores complicações da arquitetura.


Escutando o Evento

O módulo que desejar receber a notificação deverá se registrar no EventDispatcher inscrevendo uma implementação da interface EventDispatcherListener. Toda vez que o evento ocorrer, todos os listeners serão notificados do evento na mesma ordem em que foram registrados.


Notificação

  • A notificação dos listeners são feitas em série, isto é, a próxima só é feita depois que a atual retornar.
  • Embora as notificações sejam feitas na mesma Thread que gerou o evento nenhuma exceção causada pelos listeners interromperá o aviso dos próximos listener e muito menos causará rollback no evento.
  • Os eventos disparados só serão liberados para os listener quando a execução retornar para o BISFacadeInterceptor que iniciou a transação, mas antes do commit ser realizado. A este ponto, praticamente nada impedirá o commit das alterações
    • Isso quer dizer que o listener já é capaz de encontrar todas as alterações, inclusive as realizadas por outros listeners. No entanto se fizer uma chamada em outra Thread fora da transaction, as alterações não estarão visiveis ainda.


Stop 256.png
Falhas sem Rollback
Note que mesmo que o listener seja acionado dentro da mesma transação "ainda aberta" e que como suas exceptions serão ignoradas, elas não causam rollback da transação atual!! É necessário avaliar a necessidade de criar uma sub-transaction para a execução do seu código e rollback desse sub-transaction.


Disparando de Eventos

Os eventos podem ser disparados a qualquer momento através dos métodos do EventDispatcher. Atualmente o único método existente é o firePostEventsOnQueue(). Este método coloca a notificação do evento na "fila" para notificar todos os seus listeners.

Uma vez que o método termine e retorne seu processamento até o BISFacadeInterceptor todos os eventos na fila serão disparados, pouco antes do commit. Caso o "retorno" para o BISFacadeInterceptor ocorra em forma de exception, que cause o RollBack da transação, nenhum evento será disparado, já que a nada foi concluído. Evitando que os listeners recebam notificações de eventos que foram desfeitos.

Padrão de ID (nome) dos Eventos

O ID dos eventos deve ser composto pelo ID do plugin gerador do evento + nome do evento. O nome do evento pode ser separado com outro pontos, mas deve conter apenas letras minúsculas sem acento e números.

Por exemplo, o evento disparado pelo módulo BISCore deverá começar com "br.com.biserp.bis.core". Os eventos de cadastro de empresa poderiam ser "br.com.biserp.biscore.companyinsert", "br.com.biserp.biscore.companyupdate", "br.com.biserp.biscore.companydelete", etc..