Dev (Back & Front)ARTIGO

Arquitetura EDA Parte 1

Em um post no meu blog fiz uma breve introdução de uma séria de coisas como CEP, EDA e BAM. A idéia é que, em uma série, eu venha a publicar aqui uma arquitetura EDA completa. Essa arquitetura seria uma possibilidade de uso de várias tecnologias e soluções para alcançarmos uma arquitetura EDA.

Meu foco será mostrar como as tecnologias funcionam e como elas podem ser integradas com o mínimo de esforço e desenvolvimento. Gostaria que todos se sentissem a vontade para perguntar e/ou melhorar a solução de arquitetura.

Então vamos começar com o Esper. Neste artigo vou falar um pouco mais sobre o Esper, que é uma implementação de Engine de CEP tanto para Java como para .NET. Meu foco aqui é Java é claro 🙂

O Framework Esper

O Esper é uma engine de CEP escrita em Java que é muito poderoso e escalável! Como um pouquinho de esforço vou mostrar como podemos integrar o Esper com o Spring Framework e assim ganharmos mais flexibilidade e produtividade.

Nota: O Spring é carro chefe da arquitetura pois vamos utiliza-lo tanto para o com o Esper como para o ESB(ServiceMix) que é baseado em Spring, assim vamos aproveitar o modelo mental de você e uma vez se conhecendo Spring a curva de aprendizado é menor. Sem falar nas facilidades como por exemplo: Backing Beans, Transações declarativas, Arvore de Exceptions, Integração com outros frameworks, ciclo de vida e muito mais muito mais que o Spring nos oferece!

A
grande vantagem do Esper é a capacidade de processar grandes volumes de
eventos(isso ajuda a deixar a solução escalável) . O Esper funciona
como se fosse um banco de dados de cabeça para baixo. Em uma solução
de banco de dados você armazena os dados e faz as queries na horas, com
o Esper é o contrário, ou seja, você armazena as queries e os dados
você *pega* na hora!

O Esper prove uma linguagem de consulta
sobre os eventos. Essa linguagem, é o EQL que é uma DSL do tipo
*SQL-Like*. A linguagem de consulta do esper conta com diversos
recursos como funções de agregação, projeções, joins e funções. Outros
coisa que o esper prove que é fundamental nesse tipo de solução é a
query temporal. Você pode dizer que algo acontece 5mim depois de um
eventos ou depois de um query realizada.

Por exemplo esse EQL a baixo:

http://www.springsource.org/about

Essa
queries a cima do Esper faria que selecionaremos os eventos do tipo
*StockTickEvent* dos últimos 10 segundos em relação a propriedade
*timestamp*. Para uma referencia completa a EQL do Esper confiram a documentação aqui!

Esper Básico

Antes
de entrarmos na arquitetura e a junção do Esper com o Spring vamos ver
um exemplo fácil de como o Esper funciona, confira isso no código abaixo:

package com.blogspot.diegopacheco.cep.esper.samples;<br /><br />import com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest;<br />import com.espertech.esper.client.Configuration;<br />import com.espertech.esper.client.EPServiceProvider;<br />import com.espertech.esper.client.EPServiceProviderManager;<br />import com.espertech.esper.client.EPStatement;<br />import com.espertech.esper.client.EventBean;<br />import com.espertech.esper.client.UpdateListener;<br /><br />/**<br /> * Classe que mostra o funcionamento do Esper de maneira mais simples possível.<br /> *<br /> * @author Diego Pacheco<br /> * @since 26/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class EsperSimpleEasyWay {<br /><br />    public static void main(String[] args) throws Throwable {<br /><br />        // Configura e levanta a engine do esper.<br />        // perceba que aqui todos os eventos seram automaticamente<br />        // importados do pacote com.blogspot.diegopacheco.cep.esper.event.model<br />        // O Service eh criado a partir da configuracao. <br />        Configuration config = new Configuration();<br />        config.addEventTypeAutoName("com.blogspot.diegopacheco.cep.esper.event.model");<br />        EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(config);<br /><br />        // Aqui estamos criando um query.<br />        EPStatement vendaStatement = epService.getEPAdministrator().createEPL("select * from VendaRequest");<br /><br />        // Adiciono o código de tratamento a essa query.<br />        vendaStatement.addListener(new UpdateListener(){           <br />            @Override<br />            public void update(EventBean[] arg0, EventBean[] arg1) {<br /><br />                // Verifico se o resulta é da query que eu espero.<br />                if (arg0[0]!=null &&  VendaRequest.class.getSimpleName().equals(arg0[0].getEventType().getName()) ){<br />                    System.out.println("Aconreceu o evento: " + arg0[0].get("clienteId") + ", " + arg0[0].get("produtoId") );<br />                }               <br />            }<br />        });       <br /><br />        // Uma paradinha soh para dar tempo do esper subir a engine.<br />        Thread.sleep(3L);<br /><br />        // Aqui estamos criando um objeto de enveto<br />        // Estamos adicionado esse evetno ao esper<br />        // Estamos simulando a geracvao de um evento<br />        VendaRequest vreEvent = new VendaRequest( new Integer((int)(Math.random() * 10)).toString()  , new Integer((int)(Math.random() * 10)).toString(), System.currentTimeMillis());<br />        epService.getEPRuntime().sendEvent(vreEvent);<br /><br />    }<br /><br />}

Como esse
código podemos ver as funcionalidades básicas do Esper. Como vocês
devem ter percebido o Esper é baseado em POJOS, os eventos são todos
POJOS, isso facilita muito o desenvolvimento.

O Código primeiro
configura o esper, criando um objeto de configurações e dizendo onde
estão os pojos que representam eventos para o esper, você pode informar
um a um ou pode fazer como eu fiz e indicar um pacote, ai ele pega
todos os pojos desse pacote e adiciona como eventos.

Depois o
service do esper é iniciado, isso seria equivalente a subir a engine ou
contexto do esper. Essa engine sobe com as configurações que informei,
isso possibilita subir diversas engines com configurações variadas.

Isso
pode ser muito util para separar eventos externos de outras aplicações
eventos internos da própria solução que venhamos a construir, quando
chegarmos ao ESB vamos ver melhor esse questão das configurações.

Depois
é criado um query e armazenada em um EPStatement, você pode criar
quantas queries quizer, o esper processa todas e associa o resultado de
cada uma a seu respectivo EPStatement, alem disso estou adicionando um
UpdateListener ao meu EPStatement, esse é o call back do esper para
tratamento do retorno da query. O seu código de ação ou negocio seria
chamado de dentro desse call back 🙂

OK, uma parada básica para o café… Por que o engine pode não ter subido até o momento que o evento foi originado….

Então
criei um pojo chamado VendaRequest que simboliza um pedido de venda,
que é um evento esse evento é adicionado ao Esper com o código:

epService.getEPRuntime().sendEvent(vreEvent)

E pronto eras isso. Ao rodar o código você vê algo do tipo:

00:08:34,554 DEBUG [MetricReportingPath] Metrics reporting has been disabled, this setting takes affect for all engine instances at engine initialization time.<br />00:08:34,725 DEBUG [TimerServiceImpl] .startInternalClock Starting internal clock daemon thread, resolution=100<br />00:08:34,831 DEBUG [EPAdministratorImpl] .createEPLStmt statementName=null eplStatement=select * from VendaRequest<br />00:08:34,845 DEBUG [ParseHelper] .parse Parsing expr=select * from VendaRequest<br />00:08:35,187 DEBUG [ParseHelper] .parse Dumping AST...<br />00:08:35,241 DEBUG [ParseHelper] .walk Walking AST using walker com.espertech.esper.epl.parse.EPLTreeWalker<br />00:08:35,241 DEBUG [EPLTreeWalker] .leaveNode *<br />00:08:35,241 DEBUG [EPLTreeWalker] .leaveWildcardSelect<br />00:08:35,242 DEBUG [EPLTreeWalker] .leaveNode SELECTION_EXPR<br />00:08:35,242 DEBUG [EPLTreeWalker] .leaveSelectClause<br />00:08:35,242 DEBUG [EPLTreeWalker] .leaveNode EVENT_FILTER_EXPR<br />00:08:35,242 DEBUG [EPLTreeWalker] .leaveStreamFilter<br />00:08:35,243 DEBUG [EPLTreeWalker] .leaveNode STREAM_EXPR<br />00:08:35,243 DEBUG [EPLTreeWalker] .leaveStreamExpr<br />00:08:35,244 DEBUG [EPLTreeWalker] .end<br />00:08:35,244 DEBUG [ParseHelper] .walk AST tree after walking<br />00:08:35,342 DEBUG [StatementResultServiceImpl] .ctor<br />00:08:35,343 DEBUG [EventAdapterServiceImpl] .addBeanType Adding VendaRequest for type VendaRequest<br />00:08:35,481 DEBUG [FilterStreamSpecRaw] .resolveType Event type name 'VendaRequest' not resolved by plug-in event representations<br />00:08:35,494 DEBUG [FilterSpecCompiler] .makeFilterSpec spec=FilterSpecCompiled type=BeanEventType clazz=com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest parameters=[]<br />00:08:35,525 DEBUG [StatementLifecycleSvcImpl] .start Starting statement 54b94a21-794f-4ceb-ada2-b6f452871830 from desc=com.espertech.esper.core.StatementLifecycleSvcImpl$EPStatementDesc@18c56d<br />00:08:35,525 DEBUG [StatementLifecycleSvcImpl] .startInternal Starting statement 54b94a21-794f-4ceb-ada2-b6f452871830 from desc=com.espertech.esper.core.StatementLifecycleSvcImpl$EPStatementDesc@18c56d<br />00:08:35,527 DEBUG [StreamFactorySvcImpl] .createStream hashCode=29420695 filter=FilterSpecCompiled type=BeanEventType clazz=com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest parameters=[]<br />00:08:35,539 DEBUG [ViewServiceHelper] .addMergeViews Incoming specifications=[]<br />00:08:35,539 DEBUG [ViewServiceHelper] .addMergeViews Outgoing specifications=[]<br />00:08:35,549 DEBUG [ResultSetProcessorFactory] .getProcessor Getting processor for  selectionList=[com.espertech.esper.epl.spec.SelectClauseElementWildcard@110003] groupByNodes=[] optionalHavingNode=null<br />00:08:35,558 DEBUG [OrderByProcessorFactory] .getProcessor Using no OrderByProcessor<br />00:08:35,561 DEBUG [SelectExprProcessorFactory] .getProcessor Using wildcard processor<br />00:08:35,564 DEBUG [ResultSetProcessorFactory] .getProcessor Using no result processor<br />00:08:35,566 DEBUG [ViewServiceImpl] .createView No new views created, dumping stream ... com.espertech.esper.view.ZeroDepthStream@79a2e7<br />00:08:35,570 DEBUG [OutputProcessViewDirect] .ctor<br />00:08:35,570 DEBUG [EPStatementStartMethod] .start Statement start completed<br />00:08:35,570 DEBUG [EPAdministratorImpl] .createEPLStmt Statement created and started<br />00:08:35,571 DEBUG [StatementLifecycleSvcImpl] .updatedListeners No action for base implementation<br />Aconreceu o evento: 6, 1

Muito bem agora que você viu como o esper funciona, vamos colocar isso em uma infra-estrutura de arquitetura com o Spring.

Integrando o Esper ao Spring Framework

Integrar
o Esper com o Spring é tranquilo, case que natural, porem tive que
desenvolver uma pequena infra-estrutura para que poçamos configurar o
esper de forma totalemte declarativa utilizando injeção de
dependencias, para isso tive que criar uma classe Holder uma que outra
classe Helper, mas não é nada absurdo 🙂

Estrutura dos pacotes

  • com.blogspot.diegopacheco.cep.esper.core: Infra-Estrutura do Esper com Spring
  • com.blogspot.diegopacheco.cep.esper.event.bootstrap: Subir o Esper/Spring e iniciar a aplicação.
  • com.blogspot.diegopacheco.cep.esper.event.model: Os POJOS que representam os eventos.
  • com.blogspot.diegopacheco.cep.esper.event.model.service.es: Gerador de Eventos para o esper.
  • com.blogspot.diegopacheco.cep.esper.event.model.service.stmts: São Statements das queries e ações sobre os eventos do Esper.
  • com.blogspot.diegopacheco.cep.esper.samples: Contém exemplos simples e do Esper de modo puro.

Depêndencias de Jars

  • esper-3.0.0.jar
  • esperio-3.0.0.jar
  • commons-logging-1.1.1.jar
  • cglib-nodep-2.2.jar
  • antlr-runtime-3.1.1.jar
  • log4j-1.2.15.jar
  • spring-beans.jar
  • spring-context.jar
  • spring-core.jar

Estou
utilizando o Spring 2.5.6! Mas se vocês mudarems os xmls dos beans deve
funcionar com as versões antigas do Spring também, pois não uso nenheum
recurso novo. OK, chega de papo, vamos aos códigos, primeiro os POJOS
que representam eventos.

VendaRequest.Java

package com.blogspot.diegopacheco.cep.esper.event.model;<br /><br />/**<br /> * POJO que será transimitido através de um evento. Pode-se considerar<br /> * que esse POJO representa um tipo de evento chamado VendaRequest.<br /> *<br /> * @author Diego Pacheco<br /> * @since 25/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class VendaRequest {<br /><br />    private String produtoId;<br />    private String clienteId;<br />    private long timestamp;<br /><br />    public VendaRequest() {}   <br /><br />    public VendaRequest(String produtoId, String clienteId, long timestamp) {<br />        super();<br />        this.produtoId = produtoId;<br />        this.clienteId = clienteId;<br />        this.timestamp = timestamp;<br />    }<br /><br />    public String getProdutoId() {<br />        return produtoId;<br />    }<br />    public void setProdutoId(String produtoId) {<br />        this.produtoId = produtoId;<br />    }<br /><br />    public String getClienteId() {<br />        return clienteId;<br />    }<br />    public void setClienteId(String clienteId) {<br />        this.clienteId = clienteId;<br />    }<br /><br />    public long getTimestamp() {<br />        return timestamp;<br />    }<br />    public void setTimestamp(long timestamp) {<br />        this.timestamp = timestamp;<br />    }    <br /><br />    @Override<br />    public String toString() {<br />        return "VendaRequest|" + super.toString() + "|[produtoId: " + produtoId + ",clienteId: " + clienteId +<br />                ",timestamp: " + timestamp + "]";<br />    }<br /><br />}

VendaResponse.Java

package com.blogspot.diegopacheco.cep.esper.event.model;<br /><br /><br />/**<br /> * POJO que será transimitido através de um evento. Pode-se considerar<br /> * que esse POJO representa um tipo de evento chamado VendaResponse.<br /> *<br /> * @author Diego Pacheco<br /> * @since 25/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class VendaResponse {<br /><br />    private VendaRequest venda;<br />    private boolean isAchado;<br /><br />    public VendaResponse() {}   <br /><br />    public VendaResponse(VendaRequest venda,boolean isAchado) {<br />        super();<br />        this.venda       = venda;<br />        this.isAchado = isAchado;<br />    }<br /><br /><br />    public VendaRequest getVenda() {<br />        return venda;<br />    }<br />    public void setVenda(VendaRequest venda) {<br />        this.venda = venda;<br />    }<br /><br />    public boolean isAchado() {<br />        return isAchado;<br />    }<br />    public void setAchado(boolean isAchado) {<br />        this.isAchado = isAchado;<br />    }<br /><br />    @Override<br />    public String toString() {<br />        return "VendaRequest|" + venda.toString() +  ",isAchado: " + isAchado + "]";<br />    }<br /><br />}

Como podem ver são
dois POJOS simples, sendo que o VendaResponde é a respota de um
VendaRequest e tem referencia a esse outro objeto(Evento Original).
Vamos a classe que gera esses eventos.

EventSourceBean.java

package com.blogspot.diegopacheco.cep.esper.event.model.service.es;<br /><br />import com.blogspot.diegopacheco.cep.esper.core.EsperServiceHolder;<br />import com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest;<br />import com.blogspot.diegopacheco.cep.esper.event.model.VendaResponse;<br /><br />/**<br /> * Classe que representa uma fonte de eventos. Essa classe está gerando diversos eventos para o esper.<br /> *<br /> * @author Diego Pacheco<br /> * @since 26/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class EventSourceBean {<br /><br />    private EsperServiceHolder serviceHolder;<br /><br />    public void startSeeding(){<br />        // Adiciona um evento.<br />        VendaRequest vreEvent = new VendaRequest( new Integer((int)(Math.random() * 10)).toString()  , new Integer((int)(Math.random() * 10)).toString(), System.currentTimeMillis());<br />        serviceHolder.getService().getEPRuntime().sendEvent(vreEvent);<br /><br />        // Adiciona um evento.<br />        VendaResponse vrEvent = new VendaResponse(vreEvent, true);<br />        vrEvent.setAchado(true);       <br />        serviceHolder.getService().getEPRuntime().sendEvent(vrEvent);   <br />    }<br /><br />    public void setService(EsperServiceHolder serviceHolder) {<br />        this.serviceHolder = serviceHolder;<br />    }<br /><br />}

Essa classe gera os eventos
instanciando os POJOS de enventos e enviando eles ao esper através do
código: serviceHolder.getService().getEPRuntime().sendEvent(vrEvent);
Aqui o unico detalhe é que para acessar o service do Esper estou usando
o EsperServiceHolder que foi uma classe que criei para manter o
contexto do Esper acessivel a outros objetos.

Nota:
Esse cara vai ser mudado depois quando entar o ESB(ServiceMix), ai o
ESB leria de diversas fontes, protocolos, sistemas e a partir do ESB
que os eventos seriam gerados.

EsperServiceHolder.java

package com.blogspot.diegopacheco.cep.esper.core;<br /><br />import com.espertech.esper.client.Configuration;<br />import com.espertech.esper.client.EPServiceProvider;<br />import com.espertech.esper.client.EPServiceProviderManager;<br /><br />/**<br /> * Classe que é responsável por guardar a instancia do EPServiceProvider.<br /> *  <br /> * @author Diego Pacheco<br /> * @since 26/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class EsperServiceHolder {<br /><br />    private EPServiceProvider service;<br />    private Configuration config;<br /><br />    public EsperServiceHolder(Configuration config) {<br />        this.config = config;<br />        init();<br />    }<br /><br />    private void init(){<br />        service = EPServiceProviderManager.getDefaultProvider(config);<br />    }<br /><br />    public EPServiceProvider getService() {<br />        return service;<br />    }   <br />}

Esse
objeto mantem referencia ao EPServiceProvider e a Configuration, no
momento que esse objeto é instanciado pelo contexto do spring ele já
chama o init e sobe a engine do esper com esse objeto de configurações.
Vamo a classe que sobe o Spring e Esper e roda a aplicação.

EsperEngineContextBootstrap.java

package com.blogspot.diegopacheco.cep.esper.event.bootstrap;<br /><br />import org.springframework.context.ApplicationContext;<br />import org.springframework.context.support.AbstractApplicationContext;<br />import org.springframework.context.support.ClassPathXmlApplicationContext;<br /><br />import com.blogspot.diegopacheco.cep.esper.core.EsperServiceHolder;<br />import com.espertech.esper.client.EPServiceProvider;<br /><br />/**<br /> * Classe que é responsável por subir o contexto do Esper e configurar a engine<br /> * com os tipos de eventos a serem utilizados. Essa classe sobre o Contexto do Spring que por sua vez<br /> * configura e sobe o Esper.<br /> *<br /> * @author Diego Pacheco<br /> * @since 25/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class EsperEngineContextBootstrap {<br /><br />    private static ApplicationContext ac;<br /><br />    public static EPServiceProvider getEPServiceProvider(){<br />        return ((EsperServiceHolder)ac.getBean("esperServiceHolder")).getService();<br />    }<br /><br />    public static ApplicationContext getSpringApplicationContext(){<br />        return ac;<br />    }<br /><br />    public static void startUp(){<br />           ac = new ClassPathXmlApplicationContext("classpath:application-context.xml");          <br />    }<br /><br />    public static void shutdown(){       <br />        ((AbstractApplicationContext)ac).registerShutdownHook();<br />    }<br /><br />}

Essa classe
sobe o contexto do spring pelo método startup() e deruba o contexto em
um tipo de clean shutdown com o método shutdown. Ela ainda prove
facilidades para recuperar o contexto do Spring e o EPServiceProvider
do Esper.

ApplicationLauncher.java

package com.blogspot.diegopacheco.cep.esper.event.bootstrap;<br /><br />import com.blogspot.diegopacheco.cep.esper.event.model.service.es.EventSourceBean;<br /><br />/**<br /> * Classe que roda a aplicação.<br /> *<br /> * @author Diego Pacheco<br /> * @since 25/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class ApplicationLauncher {<br /><br />    public static void main(String[] args) throws Throwable {<br /><br />        // Inicia a engine do Esper.<br />        EsperEngineContextBootstrap.startUp();       <br /><br />        // Espera um pouco para dar tempo do contexto subir.<br />        Thread.sleep(3000L);<br /><br />        // Gera eventos para o Esper.<br />        EventSourceBean esBean = (EventSourceBean)EsperEngineContextBootstrap.getSpringApplicationContext().getBean("eventSourceBean");<br />        esBean.startSeeding();<br />        esBean.startSeeding();<br />        esBean.startSeeding();<br /><br />    }<br />}

Essa é a classe que serve para
rodar a aplicação, isso vai morer em breve por que dentro do ESB não
iria ser assim o proprio ESB que serviria como uma especie de
container, mas quando o ESB entrar na jogada falamos melhor sobre isso.

Agora só falta dois pontos, os Statements e as configurações de Beans no Spring. Vamos ao mecanismo de Statements primeiro!

Toda
vez que você cria um EPStatement precisa registra-lo no EPAdministrator
do Esper, então fiz uma pequeno design para que isso acontecesse de
forma injetável e configurável por següência.

StatementRegisterable.java

package com.blogspot.diegopacheco.cep.esper.core;<br /><br />import com.espertech.esper.client.EPAdministrator;<br /><br />/**<br /> * Interface que indica que o Statement do Esoer é registrável.<br /> * Assim você pode registar vários Statement com o StatementRegister.<br /> * <br /> * @author Diego Pacheco<br /> * @since 25/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public interface StatementRegisterable {<br />    public void setEPAdministrator(EPAdministrator admin);<br />}

Esse interface é um tipo de observer nesse solução. Um observer de registro, esntranho não ? 🙂
Vamos a classe genérica que registra os Statements de forma automatizada e injetável.

StatementRegister.java

package com.blogspot.diegopacheco.cep.esper.core;<br /><br />import java.util.List;<br /><br /><br />/**<br /> * Classe que registra um conjunto de StatementRegisterable no mesmo EPAdministrator de um service.<br /> * <br /> * @author Diego Pacheco<br /> * @since 25/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class StatementRegister {   <br /><br />    private EsperServiceHolder serviceHolder;<br /><br />    public StatementRegister(EsperServiceHolder serviceHolder){<br />        this.serviceHolder = serviceHolder;<br />    }<br /><br />    /**<br />     * Metodo que registra o EPAdministrator para um conjunto de StatementRegisterable;<br />     *<br />     * @param admin instancia de EPAdministrator<br />     * @param stmts instancia de StatementRegisterable<br />     */<br />    public void registerStatements(List<statementregisterable> stmts){<br />        for(StatementRegisterable stmt: stmts){<br />            stmt.setEPAdministrator(serviceHolder.getService().getEPAdministrator());<br />        }<br />    }   <br />}

Esse
cara tem o método *registerStatements* que é onde acontece toda a
mágina, ele passa a intancia do EPAdministrator para todos os
Statements para que eles possam se registrar, seria como se fosse um
EPAdministratorAware. Uffa uma classe só, o Statement agora.

package com.blogspot.diegopacheco.cep.esper.event.model.service.stmts;<br /><br />import com.blogspot.diegopacheco.cep.esper.core.StatementRegisterable;<br />import com.blogspot.diegopacheco.cep.esper.event.model.VendaResponse;<br />import com.espertech.esper.client.EPAdministrator;<br />import com.espertech.esper.client.EPStatement;<br />import com.espertech.esper.client.EventBean;<br />import com.espertech.esper.client.UpdateListener;<br /><br /><br />/**<br /> * Classe que processa o evento de vendas. Aqui adicionamos as querys sobre<br /> * os eventos de vendas e bem como o processamento das ações em cima desses<br /> * eventos.<br /> *<br /> * @author Diego Pacheco<br /> * @since 25/02/2009<br /> * @version 1.0<br /> *<br /> */<br />public class VendaStatement implements StatementRegisterable{<br /><br />    private EPAdministrator admin;<br />    private EPStatement vendaStatement;<br /><br />    public VendaStatement() {}<br /><br />    private void setUp(){       <br /><br />        // Adiciono a query.<br />        vendaStatement = admin.createEPL("select * from VendaResponse");<br /><br />        // Adiciono o código de tratamento a essa query.<br />        vendaStatement.addListener(new UpdateListener(){           <br />            @Override<br />            public void update(EventBean[] arg0, EventBean[] arg1) {<br /><br />                // Verifico se o resulta é da query que eu espero.<br />                if (arg0[0]!=null &&  VendaResponse.class.getSimpleName().equals(arg0[0].getEventType().getName()) ){<br />                    System.out.println("Aconreceu o evento: " + arg0[0].get("clienteId") + ", " + arg0[0].get("produtoId") );<br />                }               <br />            }<br />        });<br />    }<br /><br />    @Override<br />    public void setEPAdministrator(EPAdministrator admin) {<br />        this.admin = admin;<br />        setUp();<br />    }<br /><br />}

Essa classe implementa
StatementRegisterable, também cria seu proprio Statement e associa uma
query e uma call back a essa query, a query aqui é simples, pois meu
propósito é mostrar a coisa toda funcionando.

Configurações agora! Primeiro vamos ao básico log4j.xml

<?xml version="1.0" encoding="UTF-8"?><br /><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"><br /><br /><log4j:configuration log4j="http://jakarta.apache.org/log4j/" debug="false"><br /><br />   <appender name="terminal" class="org.apache.log4j.ConsoleAppender"><br />      <param name="Threshold" value="DEBUG"><br />      <param name="Target" value="System.out"><br />      <layout class="org.apache.log4j.PatternLayout"><br />         <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"><br />      </layout><br />   </appender><br /><br />   <logger name="com.espertech.esper"><br />      <level value="DEBUG"><br />   </logger><br /><br />   <logger name="org.springframework"><br />      <level value="INFO"><br />   </logger><br /><br />   <root><br />      <level value="WARN"><br />      <appender-ref ref="terminal"><br />   </root><br /><br /></log4j:configuration>

Nada
de mais, dois loggers, spring e esper, você pode configurar o level se
quizer ver mais o que está acontecnedo, mas esse nivél já é muito bom.

Existem 4 arquivos do Spring, são eles:

  • application-context.xml: Junta todos os outros 3 arquivos via import.
  • spring-esper-context-beans.xml: Beans responsáveis pelo contexto do Esper e Confs.
  • spring-esper-es-beans.xml: Beans que são fontes geradoras de eventos.
  • spring-esper-stmts-beans.xml: Beans Statements do Esper.

Vamos ao código dos 4 então. application-context.xml

<?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-instance" p="http://www.springframework.org/schema/p" aop="http://www.springframework.org/schema/aop" context="http://www.springframework.org/schema/context" schemalocation="http://www.springframework.org/schema/beans                                                 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                                                http://www.springframework.org/schema/aop                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd                            http://www.springframework.org/schema/context                            http://www.springframework.org/schema/context/spring-context-2.5.xsd" autowire="no" check="none" init="true"><br /><br />    <import resource="classpath:spring-esper-context-beans.xml"><br />    <import resource="classpath:spring-esper-stmts-beans.xml">   <br />    <import resource="classpath:spring-esper-es-beans.xml">   <br /><br /></beans>

spring-esper-context-beans.xml

<?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-instance" p="http://www.springframework.org/schema/p" aop="http://www.springframework.org/schema/aop" context="http://www.springframework.org/schema/context" schemalocation="http://www.springframework.org/schema/beans                                                 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                                                http://www.springframework.org/schema/aop                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd                            http://www.springframework.org/schema/context                            http://www.springframework.org/schema/context/spring-context-2.5.xsd" autowire="no" check="none" init="true"><br />    <!-- Beans de configuração do provider do Esper. --><br />    <bean id="esperConfig" class="com.espertech.esper.client.Configuration" scope="singleton" init="false">   <br /><br />    <!--           Aqui estou adicionado o pacote(com.blogspot.diegopacheco.cep.esper.event.model) que contem          os beans event types do esper. Tudo isso via invocação de metodo com o Spring :)          Essa invocação só ocorre uma vez.     -->           <br />    <bean id="setupEsperConfiguration" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"><br />          <property name="targetObject" ref="esperConfig"><br />          <property name="targetMethod" value="addEventTypeAutoName"><br />          <property name="arguments" value="com.blogspot.diegopacheco.cep.esper.event.model"><br />    </bean><br />    <bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">   <br />        <property name="delay" value="0"><br />        <property name="period" value="0"><br />        <property name="timerTask" ref="setupEsperConfiguration"><br />    </bean><br />    <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean" init="false"><br />        <property name="scheduledTimerTasks"><br />            <list><br />                <ref bean="scheduledTask"><br />            </list><br />        </property><br />    </bean>       <br /><br />    <!-- Bean que mantem o esngine de cep do esper no ar, nesse caso gerenciado pelo Spring :)          Este bean tem o metodo getService() que permite obter o EPServiceProvider jah configurado.             --><br />    <bean id="esperServiceHolder" class="com.blogspot.diegopacheco.cep.esper.core.EsperServiceHolder"><br />        <constructor-arg index="0"><br />          <ref bean="esperConfig"><br />        </constructor-arg><br />    </bean>       <br /><br /></beans>

Nesse
arquivo está o bean de configurações do Esper e de forma declarativa
injetei a execução do método que confgira os pacotes que auto
transforman beans em eventos, existe também o bem que segura o service
do Esper que é o esperServiceHolder.

spring-esper-es-beans.xml

<?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-instance" p="http://www.springframework.org/schema/p" aop="http://www.springframework.org/schema/aop" context="http://www.springframework.org/schema/context" schemalocation="http://www.springframework.org/schema/beans                                                 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                                                http://www.springframework.org/schema/aop                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd                            http://www.springframework.org/schema/context                            http://www.springframework.org/schema/context/spring-context-2.5.xsd" autowire="no" check="none" init="true"><br /><br />    <!-- Beans que são es: Fontes de de eventos, esses beans geram os eventos para o esper. -->   <br /><br />    <bean id="eventSourceBean" class="com.blogspot.diegopacheco.cep.esper.event.model.service.es.EventSourceBean"><br />        <property name="service"><br />            <ref bean="esperServiceHolder"><br />        </property><br />    </bean><br /><br /></beans>

Esse é fácil, é a declaração do bean gerador de eventos.

spring-esper-stmts-beans.xml

<?xml version="1.0" encoding="UTF-8"?><br /><beans xmlns="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-instance" p="http://www.springframework.org/schema/p" aop="http://www.springframework.org/schema/aop" context="http://www.springframework.org/schema/context" schemalocation="http://www.springframework.org/schema/beans                                                 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                                                http://www.springframework.org/schema/aop                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd                            http://www.springframework.org/schema/context                            http://www.springframework.org/schema/context/spring-context-2.5.xsd" autowire="no" check="none" init="true"><br /><br />    <!-- Bem que faz a passagem do administrador do esper para os beans de statements          para que eles posssam se registrar no engine do esper.      --><br />    <bean id="statementRegister" class="com.blogspot.diegopacheco.cep.esper.core.StatementRegister"><br />        <constructor-arg index="0"><br />            <ref bean="esperServiceHolder"><br />        </constructor-arg><br />    </bean>   <br /><br /><br />    <!-- Registro de stmts na engine do Esper. --><br />    <bean id="setupEsperStmts" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"><br />          <property name="targetObject" ref="statementRegister"><br />          <property name="targetMethod" value="registerStatements"><br />          <property name="arguments" ref="stmts"><br />    </bean><br />    <bean id="scheduledTaskStmts" class="org.springframework.scheduling.timer.ScheduledTimerTask">   <br />        <property name="delay" value="0"><br />        <property name="period" value="0"><br />        <property name="timerTask" ref="setupEsperStmts"><br />    </bean><br />    <bean id="timerFactoryStmts" class="org.springframework.scheduling.timer.TimerFactoryBean" init="false"><br />        <property name="scheduledTimerTasks"><br />            <list><br />                <ref bean="scheduledTaskStmts"><br />            </list><br />        </property><br />    </bean><br /><br />    <!--         Statemtens: Tem as queries do esper e o processamento de resposta.     -->   <br />    <bean id="stmts" class="java.util.ArrayList"><br />        <constructor-arg index="0"><br />            <list><br />                <bean class="com.blogspot.diegopacheco.cep.esper.event.model.service.stmts.VendaStatement">                               <br />            </list><br />        </constructor-arg><br />    </bean>   <br /><br /></beans>

Aqui
temos 2 coisas, a declaração de todos os statements do sistema no bean
stmts, e o registro automativo do EPAdministrador nesses Statemetns,
isso é feito via injeção de método com o
MethodInvokingTimerTaskFactoryBean do Spring.

Pronto já temos um
arquitetura básica integrada entre o Esper o Spring, o próximo passo é
colocar o ESB(ServiceMix) ai vamos modificar o código dos beans
geradores de eventos e vamos adicionar coisas bem interessantes, mas
isso é no próximo post.

é Técnico em Processamento de Dados e graduando em Ciências da Computação(7º sem.) na Ulbra. Já trabalhou com desenvolvimento de software em VB, ASP, .NET e PHP. Atualmente é Arquiteto de Software criando soluções corporativas em Java. Certificado pela SUN com SCJP 5 e SCWD 5. Mantém o blog (diego-pacheco.blogspot.com).

Ver perfil