Erro com Vraptor e JPA[RESOLVIDO]

Boa tarde galera estou usando o vraptor e JPA hibernate em meu projeto sei que vraptor faz o flush sozinho e tals, só que com isso eu não consigo retornar uma mensagem para o meu usuário, daí para resolver isso eu faço o flush no metodo delete por exemplo, mas quando tenho um registro vinculado a outro ele dá uma excepetion, que acredito que depois que da a PersistenceException depois que eu forcei o flush, ele executa novamente o o commit, espero que tenho conseguido passar o meu problema.

em poucas palavras gostaria de saber como faço para não executar o commit que o vraptor faz…

segue parte do meu código:

Controller:

@Path("/excluirContador/{contador.idcontador}")
	public void excluirContador(Contador contador) {

		try {
			...
			
			repository.delete(contador);
		} catch (PersistenceException ex) {
			result.include("mensagem",
					"Não é permitido excluir esse registro, esta vinculado a outro(s) registro(s)");
			result.include("categoria", "erro");
		} catch (Exception ex) {
			result.include("mensagem",
					"Ocorreu um erro inesperado, se persistir o erro, entre em contado com suporte");
			result.include("categoria", "erro");
		}
		result.forwardTo(this).contador(paginacao.getSelecionado());

	}

minha business (GenericBusiness):

public void delete(Object id) throws Exception {
		try {
			manager.remove(manager.getReference(clazz, id));
			manager.flush();			
		} catch (PersistenceException persistenceException) { 
		
			manager.getTransaction().rollback();
			throw new PersistenceException(" Erro ");
		} catch (Exception ex) {
			manager.getTransaction().rollback();
			throw new Exception(" Erro ");
		}

	}

a exception que gera:

java.lang.IllegalStateException: Transaction not active
	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:69)
	at br.com.caelum.vraptor.util.jpa.JPATransactionInterceptor.intercept(JPATransactionInterceptor.java:53)
	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.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.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.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.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:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Thread.java:679)

não entendi o problema…

vc deu o flush depois do remove e mesmo assim não soltou exception?

vc não precisa dar rollback se estiver usando o pacote .jpa no web.xml, o VRaptor vai dar esse rollback automaticamente em caso de erro

Bom é o seguinte eu tento excluir um registro que esta vinculado a outro no momento que ele der o flush, será gerado uma exception do tipo PersistenceException certo?

se no metodo eu deixar somente assim:


manager.remove(manager.getReference(clazz, id));
...
catch (PersistenceException persistenceException) { //
	throw new PersistenceException(" Erro ");

ele não gera a exception que eu quero que gere no caso PersistenceException, para que eu possa recuperar ela e enviar para o usuário que a mensagem que não pode ser excluido.

mas se eu fizer da form abaixo:


manager.remove(manager.getReference(clazz, id));
manager.flush();
...
catch (PersistenceException persistenceException) { //
	throw new PersistenceException(" Erro ");

ele faz o que eu quero, só que porém ele gera a exception:

SEVERE: Servlet.service() for servlet default threw exception
javax.persistence.RollbackException: Transaction marked as rollbackOnly
	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:73)
	at br.com.caelum.vraptor.util.jpa.JPATransactionInterceptor.intercept(JPATransactionInterceptor.java:53)
	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.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.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:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Thread.java:679)

pelo que eu entendi ele tenta dar o commit denovo que é o do vraptor, daí a pergunta como eu faço para deixar somente o FLUSH do meu metodo delete, ou qual a melhor forma para atender as minhas necessidades.

espero que eu tenha conseguido passar o meu problema, desculpe se esta meio confuso.

a idéia é não dar mais a exception, certo?

vc vai precisar sobrescrever o comportamento do JPATransactionInterceptor…

um dos jeitos é ignorando o RollbackException:

@Intercepts(before=JPATransactionInterceptor.class)
public class IgnoradorInterceptor implements Interceptor {
   //accepts true
   public void intercept(...) {
      try {
           stack.next(...);
      } catch (RollbackException e) {
          //ignora, faz um log, talvez, e NÃO relança a exception
      }
   }
}

esse é o mais simples, então tenta aí…

só cuidado pra não cair em casos zuados, então pelo menos faça o log da exception

Teria uma forma de eu não sobscrever o o comportamento do JPA, mas eu enviar uma mensagem para o meu usuário que não é permitido excluir o registro?

se deu o rollbackException é pq deu uma exception e vc tratou.

se eu não tratar ele não chega a dar commit, então não dá o RollbackException.

pode fazer esse Interceptor sem dó :wink: ele vai executar sempre que vc fizer o catch em uma Exception da jpa e não relançar

Lucas eu não entendi muito bem, o que deve fazer, se você puder me explicar melhor, eu devo fazer algo do tipo:

package br.com.coliseu.util;

import javax.persistence.EntityManager;
import javax.persistence.RollbackException;

import br.com.caelum.vraptor.InterceptionException;
import br.com.caelum.vraptor.Intercepts;
import br.com.caelum.vraptor.core.InterceptorStack;
import br.com.caelum.vraptor.interceptor.Interceptor;
import br.com.caelum.vraptor.resource.ResourceMethod;
import br.com.caelum.vraptor.util.jpa.JPATransactionInterceptor;

@Intercepts(before = JPATransactionInterceptor.class)
public class IgnoradorInterceptor implements Interceptor {

	private final EntityManager manager;

	public IgnoradorInterceptor(EntityManager manager) {
		this.manager = manager;
	}

	public boolean accepts(ResourceMethod method) {
		return true;
	}

	public void intercept(InterceptorStack stack, ResourceMethod method,
			Object resourceInstance) throws InterceptionException {
		try {
			stack.next(method, resourceInstance);

		} catch (RollbackException e) {
			manager.getTransaction().rollback();

		}

	}

}

GenericBusiness

public void delete(Object id) throws Exception {
	manager.remove(manager.getReference(clazz, id));
	manager.flush();
	

	}

Controller:

@Path("/excluirContador/{contador.idcontador}")
	public void excluirContador(Contador contador) {

		try {
			paginacao.setUrl("/contador");
			result.include("paginacao", paginacao);
			repository.delete(contador.getIdcontador());
		} catch (PersistenceException ex) {
			result.include("mensagem",
					"Não é permitido excluir esse registro, esta vinculado a outro(s) registro(s)");
			result.include("categoria", "erro");
		} catch (Exception ex) {
			result.include("mensagem",
					"Ocorreu um erro inesperado, se persistir o erro, entre em contado com suporte");
			result.include("categoria", "erro");
		}
		result.forwardTo(this).contador(paginacao.getSelecionado());

	}

se puder por gentileza deixar um pouco mais claro a sua ideia, porque eu sou um pouco leigo no assunto ainda.

obrigado!

só não precisa do manager.getTransaction().rollback()… o próprio vraptor vai fazer isso.

a explicação é meio complicada… mas básicamente se deu uma exception ele marca a transação como rollback-only. Se está assim eu não posso chamar o commit() senão ele lança o RollbackException.

se vc trata a exception o vraptor vai chamar o commit() e dá o pau.

Agora eu entendi, value Lucas.

Obrigado.