Dúvidas sobre comportamentos do VRaptor[Resolvido]

11 respostas
worldsoft

Olá galera, estou com uma pequena dúvida:

Tenho uma aplicação que usa hibernate, e eu controlo a abertura e fechamento das trasações em um @Interceptor do vraptor, o problema é que quando executo um delete por exemplo, numa linha de uma tabela que faz referencia a outra tabela é gerado uma ConstraintViolationExecption–Acho que é esse o nome–, até ai tudo bem pois consigo capturar essa exception e trata-la, o problema é que não estou conseguindo enviar a view uma mensagem para o usuário dizendo que a linha está sendo referenciada a uma outra tabela, pois o vraptor já escreveu e commito o response da requisição.

Ex:
Obs.: Não tenho a classe toda aqui, e também não me lembro de todos os comandos de cabeça mais o problema é +/- isso:

try{
   Transaction tx = this.session.beginTransaction();
   stack.next(method, instance); 
   controller.commit();
}catch(ConstraintViolationException cvEx){
   if (tx.isActive) tx.rolback();
   //Aqui preciso enviar algo ao view, mais não consigo pois o response já está comitado
}

11 Respostas

Lucas_Cavalcanti

o seu interceptor só commita a transação depois que a view foi mostrada. E o erro só acontece no commit da transação, então já não há mais nada que pode ser feito.

Um jeito de resolver isso é criar dois interceptors, um que roda antes do controller (e da begin na tx), e um que roda logo depois do controller (antes de mostrar a view e dá commit na tx). Tb vai ser preciso colocar um redirect listener, pra dar commit na tx assim que acontecer um redirect tb.

essa solução parece boa pra vc? quer ajuda pra implementá-la?

worldsoft

Serve sim, se você poder me ajudar eu ficaria agradeçido…

Lucas_Cavalcanti

se vc sempre segue o padrão Redirect after post (ou seja, sempre que alterar algo no banco usar POST, e dar um redirect no final do método), dá pra implementar isso de um jeito mais fácil.

receba um MutableResponse do VRaptor no construtor do controller e faça:

try{  
   Transaction tx = this.session.beginTransaction();  
   response.addRedirectListener(new RedirectListener() {
        public void beforeRedirect() {
            tx.commit();
        }
   });
   stack.next(method, instance);   
   if (tx.isActive) tx.commit();  
}catch(ConstraintViolationException cvEx){  
   if (tx.isActive) tx.rolback();  
}

assim antes de fazer o redirect o vraptor vai chamar o listener e commitar a transação, e vai dar o erro antes do VRaptor executar o redirect de fato e vc vai conseguir capturar a exceção no momento certo

worldsoft

Lucas Cavalcanti:
se vc sempre segue o padrão Redirect after post (ou seja, sempre que alterar algo no banco usar POST, e dar um redirect no final do método), dá pra implementar isso de um jeito mais fácil.

receba um MutableResponse do VRaptor no construtor do controller e faça:

try{  
   Transaction tx = this.session.beginTransaction();  
   response.addRedirectListener(new RedirectListener() {
        public void beforeRedirect() {
            tx.commit();
        }
   });
   stack.next(method, instance);   
   if (tx.isActive) tx.commit();  
}catch(ConstraintViolationException cvEx){  
   if (tx.isActive) tx.rolback();  
}

assim antes de fazer o redirect o vraptor vai chamar o listener e commitar a transação, e vai dar o erro antes do VRaptor executar o redirect de fato e vc vai conseguir capturar a exceção no momento certo

Desta forma no catch eu consigo incluir valores para ser apresentado na view, tipo:

try{  
   Transaction tx = this.session.beginTransaction();  
   response.addRedirectListener(new RedirectListener() {
        public void beforeRedirect() {
            tx.commit();
        }
   });
   stack.next(method, instance);   
   if (tx.isActive) tx.commit();  
}catch(ConstraintViolationException cvEx){  
   result.include(new ValidationMessages(Arrays.asList("Erro ao deletar linha!"));
   if (tx.isActive) tx.rolback();  
}
Lucas_Cavalcanti

consegue, mas vc vai ter que redirecionar o request pra algum lugar, ele não vai fazer isso automaticamente…

dá pra tentar pegar a lógica que vc configurou no validator, isso é suficiente?

worldsoft

Lucas Cavalcanti:
consegue, mas vc vai ter que redirecionar o request pra algum lugar, ele não vai fazer isso automaticamente…

dá pra tentar pegar a lógica que vc configurou no validator, isso é suficiente?


Sim, acho que isso resolve o meu problema, vou testar a noite quando chegar em casa, e posto a resposta…

Por enquando, obrigado pela ajuda.

worldsoft

worldsoft:
Lucas Cavalcanti:
consegue, mas vc vai ter que redirecionar o request pra algum lugar, ele não vai fazer isso automaticamente…

dá pra tentar pegar a lógica que vc configurou no validator, isso é suficiente?


Sim, acho que isso resolve o meu problema, vou testar a noite quando chegar em casa, e posto a resposta…

Por enquando, obrigado pela ajuda.

Lucas funcionou tudo beleza, obrigado pela ajuda.

worldsoft

Lucas Cavalcanti:
consegue, mas vc vai ter que redirecionar o request pra algum lugar, ele não vai fazer isso automaticamente…

dá pra tentar pegar a lógica que vc configurou no validator, isso é suficiente?

Lucas deixa eu te encher o saco mais um pouco, cara não estou conseguindo pegar as exceções correta, por exemplo:
Digamos que dois usuários ao mesmo tempo tenta excluir a mesma linha no banco de dados,sei que o hibernate executa uma requisição por vez e --ai vem o problema-- não consigo pegar a exception correta que seria ObjectNotFoundException para a segunda requisição, pois a exception principal que chega até o meu bloco cacth é um InteceptionException, o que devo fazer para resolver esse pequeno problema?

worldsoft

Essa é stack trace apresentada:

br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [br.com.tsoftnet.atlas.administration.models.City#8] at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:96) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.tsoftnet.atlas.persistence.Filter.Persistence.intercept(Persistence.java:78) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.tsoftnet.atlas.infrastructure.view.AccessManager.intercept(AccessManager.java:43) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:89) at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:23) at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92) at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58) at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:662) Caused by: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [br.com.tsoftnet.atlas.administration.models.City#8] at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:435) at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:189) at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:178) at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215) at org.hibernate.engine.StatefulPersistenceContext.unproxyAndReassociate(StatefulPersistenceContext.java:619) at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:89) at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:73) at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:956) at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:934) at br.com.tsoftnet.atlas.persistence.DaoGeneric.delete(DaoGeneric.java:55) at br.com.tsoftnet.atlas.administration.controller.CityController.delete(CityController.java:128) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:61) ... 49 more

Lucas_Cavalcanti

vc pode tentar dar try…catch(ONFE e) dentro do controller ou do dao.

ou ainda usar:

result.on(ObjectNotFoundException.class).notFound();

ou algo do tipo.

worldsoft

Lucas Cavalcanti:
vc pode tentar dar try…catch(ONFE e) dentro do controller ou do dao.

ou ainda usar:

result.on(ObjectNotFoundException.class).notFound();

ou algo do tipo.

Lucas desculpa meu amadorismo, agora eu entendi como está funcionando está rotina que você me ajudou a implementar, o commit da transação está acontecendo antes que eu mande redirecionar para algum lugar, por isso consigo pegar alguma exceção do hibernate dentro do controler…

Foi mau…

Obrigado mais uma vez.

Criado 18 de julho de 2011
Ultima resposta 22 de jul. de 2011
Respostas 11
Participantes 2