Observer em um Resources do vraptor

18 respostas
L

Pesoal,

Tenho alguns métodos em um controller que estão fazendo mais de uma coisa e estou querendo refatorá-los para um observer. É um problema bem parecido com a classe GeradorDeNotaFiscal desse post:http://blog.caelum.com.br/tdd-e-sua-influencia-no-acoplamento-e-coesao/

No caso esse controller seria observado e os observadores seriam recebidos no construtor:

public controller(Observer1 o1, Observer2 o2) {
  o1 = new Observer1(this);
  o2 = new Observer2(this);
}

No controller também teriam os métodos para adicionar observer e notificação.

Tem outra forma de implementar esse observer no controller ou dessa forma está ok?

18 Respostas

Lucas_Cavalcanti

como vc pensa em fazer com que requisições sejam transformadas em observers?

L

Os observers só iriam salvar ou atualizar alguns dados no banco.

public controller(Observer1 o1, Observer2 o2, Repository r1, Repository r2) {  
      o1 = new Observer1(this, r1);  
      o2 = new Observer2(this, r2);  
    }
Lucas_Cavalcanti

pode dar um exemplo mais concreto?

L

Imagina um controller parecido com essa classe GeradorDeNotaFiscal:

public class GeradorDeNotaFiscal {
       private final Sap sap;
       private final EnviadorDeEmails enviador;
 
       public GeradorDeNotaFiscal(Sap sap, EnviadorDeEmails enviador) {
               this.sap = sap;
               this.enviador = enviador;
       }
 
       private NotaFiscal geraNotaFiscalAPartirDa(Fatura fatura) {
          
       }
 
       public void gera(Fatura fatura) {
               NotaFiscal nf = geraNotaFiscalAPartirDa(fatura);
 
               sap.armazena(nf);
               enviador.envia(nf);
       }
}

Agora sap e EnviadorDeEmails seriam Observers:

public class GeradorDeNotaFiscalController {
       private final Sap sap;
       private final EnviadorDeEmails enviador;
 
       public GeradorDeNotaFiscalController(Sap sap, EnviadorDeEmails enviador) {
               this.sap = new Sap(this);
               this.enviador = new EnviadorDeEmails(this);
       }
 
       private NotaFiscal geraNotaFiscalAPartirDa(Fatura fatura) {
          
       }

       public void notifica(Nota Fiscal) {

       }
 
       public void gera(Fatura fatura) {
               NotaFiscal nf = geraNotaFiscalAPartirDa(fatura);
 
               notifica(nf);
       }
}
Lucas_Cavalcanti

se vc recebe o Sap e o EnviadorDeEmails como dependência, vc não deveria dar new neles:

public class GeradorDeNotaFiscalController {  
       private final Sap sap;  
       private final EnviadorDeEmails enviador;  
  
       public GeradorDeNotaFiscalController(Sap sap, EnviadorDeEmails enviador) {  
               this.sap = sap;  
               this.enviador = enviador;  
       }
}

esse controller é um @Resource?

L

É porque em Sap eu teria que receber o controller no construtor.
Algo assim:

public Sap(GeradorDeNotaFiscalController controller){
		controller.adicionarObservador(this);
	}
Lucas_Cavalcanti

aí que está, vc não precisa do adicionaObservador, já que vc tá recebendo o Sap no construtor do controller…

o ideal na verdade é vc criar uma interface:

public interface NotaFiscalObserver /*extends Observer?*/ {
   //...
}

e fazer com que o Sap e o EnviadorDeEmails implementem essa interface. Eles também devem ser anotados com @Component.

Daí vc pode receber no controller uma List:

@Resource
public class GeradorDeNotaFiscalController {    
       
       public GeradorDeNotaFiscalController(List<NotaFiscalObserver> observers) {    
            this.observers = observers;
       }
       public void notifica(Fatura fatura) {
           for (NotaFiscalObserver obs : this.observers) {
               obs.notifica(fatura);
           }
       }
}

ou algo do tipo. Assim, se vc precisar adicionar outro observer é só criar uma classe anotada com @Component que implementa NotaFiscalObserver, não precisa modificar o controller.

Lembrando: o Sap e o EnviadorDeEmails não precisam receber o controller!

Edufa

Lucas Cavalcanti:
aí que está, vc não precisa do adicionaObservador, já que vc tá recebendo o Sap no construtor do controller…

o ideal na verdade é vc criar uma interface:

public interface NotaFiscalObserver /*extends Observer?*/ {
   //...
}

e fazer com que o Sap e o EnviadorDeEmails implementem essa interface. Eles também devem ser anotados com @Component.

Daí vc pode receber no controller uma List:

Curiosidade

public GeradorDeNotaFiscalController(List<NotaFiscalObserver> observers) {

observers vai receber todos as classes que implementam NotaFiscalObserver ?

Lucas_Cavalcanti

exato!

isso só funciona automaticamente se vc usa o Spring como DI (se vc está com os jars do spring no WEB-INF/lib), pro Guice tem que fazer uma configuraçãozinha e pro Pico eu não tenho certeza, mas é possível que funcione também.

Edufa

Isto é muito legal !
poderia ver o q tem de fazer no Guice, atualmente estou usando apenas ele.

[]s

Lucas_Cavalcanti

no guice vc precisa configurar essa List<…> explicitamente…

tem um jeito relativamente fácil de fazer isso, mas tá protected no VRaptor…

se vc não se importar de usar snapshots, posso gerar um pra vc com essa alteração

Edufa

eu gostaria sim, se não for incomodo, com o snapshot não posso colocar em produção, mas poderei testar internamente.

[]

Lucas_Cavalcanti

Testa aí

Edufa

Apareceu um erro estranho

2011-03-28 22:51:11.861:INFO::jetty-7.3.0.v20110203
2011-03-28 22:51:13.554:WARN::Failed startup of context o.m.j.p.JettyWebAppContext{/,file:/E:/trabalho/workspace/aws2/src/main/webapp/},file:/E:/trabalho/workspace/aws2/src/main/webapp/
java.lang.IllegalStateException: Duplicate fragment name: @@-NAMELESS-@@0 for jar:file:/E:/trabalho/repositorio/br/com/caelum/vraptor/3.3.2-SNAPSHOT/vraptor-3.3.2-SNAPSHOT.jar!/META-INF/web-fragment.xml and jar:file:/E:/trabalho/workspace/aws2/src/main/webapp/WEB-INF/lib/vraptor-3.3.1.jar!/META-INF/web-fragment.xml
	at org.eclipse.jetty.webapp.MetaData.addFragment(MetaData.java:244)
	at org.eclipse.jetty.webapp.FragmentConfiguration.findWebFragments(FragmentConfiguration.java:72)
...

Usando eclipse+maven+jetty7

Arranquei o fragment e voltou a funcionar…

mas não sei se teve a ver a atualização ou algumas mexidas que eu tinha feito no pom

Lucas_Cavalcanti

o vraptor inclui um fragment do servlet 3.0, e vc está com dois jars do vraptor, por isso o erro de name duplicado.

Edufa

Obrigado o maven estava com um lixo … mas agora testando surgiu este erro, com a versão 3.3.1 funciona com a 3.3.2-SNAPSHOT ele aparece …

2011-03-30 15:17:20.997:WARN::Error for /
java.lang.NoClassDefFoundError: br/com/caelum/vraptor/vraptor2/Info
	at br.com.caelum.vraptor.util.StringUtils.lowercaseFirst(StringUtils.java:35)
Lucas_Cavalcanti

usa esse snapshot:
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.3.2-SNAPSHOT/vraptor-3.3.2-20110329.205836-1.jar

Edufa

Agora funcionou !

Obrigado

Criado 25 de março de 2011
Ultima resposta 30 de mar. de 2011
Respostas 18
Participantes 3