VRaptor 3.2 - Erro redirecionamento: java.lang.IllegalStateException [RESOLVIDO]

10 respostas
bronx

Caros foristas,

Tenho notado nos logs da minha aplicação a ocorrência, com certa frequência, de um IllegalStateException durante a execução da aplicação (em produção):

Jan 10, 2011 3:46:49 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet default threw exception
br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: java.lang.IllegalStateException
	at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:86)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:69)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:90)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:42)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.util.hibernate.HibernateTransactionInterceptor.intercept(HibernateTransactionInterceptor.java:45)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:44)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:81)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:70)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56)
	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:230)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at br.com.locaweb.tomcat.LocaWebValve.invoke(LocaWebValve.java:134)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
	at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
	at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:283)
	at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:767)
	at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:697)
	at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:889)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:686)
	at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.IllegalStateException
	at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)
	at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:126)
	at br.com.caelum.vraptor.http.VRaptorResponse.sendRedirect(VRaptorResponse.java:46)
	at br.com.caelum.vraptor.view.DefaultLogicResult$2.intercept(DefaultLogicResult.java:124)
	at br.com.caelum.vraptor.proxy.AbstractCglibProxifier$2.intercept(AbstractCglibProxifier.java:56)
	at br.com.scv.controller.MenuPrincipalController$$EnhancerByCGLIB$$dcb312e9.inicio(<generated>)
	at br.com.scv.controller.LoginController.logar(LoginController.java:93)
	at sun.reflect.GeneratedMethodAccessor269.invoke(Unknown Source)
	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:57)
	... 51 more

O que ocorre: após efetuar login, o usuário é redirecionado ao menu principal da aplicação (at br.com.scv.controller.LoginController.logar(LoginController.java:93)). Daí em diante o que é executado é o proxy do controller para qual eu redirecionei a navegação (at br.com.scv.controller.MenuPrincipalController$$EnhancerByCGLIB$$dcb312e9.inicio()).
O ponto é que, aparentemente, o erro não ocorre exatamente dentro do meu código, e sim no proxy criado pelo VRaptor (a “view”). Estou certo?

Alguém também já passou por isso?

Alguma ideia do que possa ser?

Abç

10 Respostas

bronx

Esqueci de dizer que esse erro ocorre pouquíssimas vezes. Geralmente funciona sem problemas…!

bronx

Andei investigando aqui, mas preciso estudar mais a fundo a parada.

Se liga:

A linha onde ocorre o erro é essa aqui: org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)
Pesquisando o código fonte, encontrei a referia classe e método:

///////////Classe org.apache.catalina.connector.ResponseFacade
  431       public void sendRedirect(String location)
  432           throws IOException {
  433   
  434           if (isCommitted())
  435               throw new IllegalStateException
  436                   (/*sm.getString("responseBase.reset.ise")*/);
  437   
  438           response.setAppCommitted(true);
  439   
  440           response.sendRedirect(location);
  441   
  442       }

Podemos ver que a exceção é lançada caso o método isCommited() retorne true. Vejamos este método:

///////////Classe org.apache.catalina.connector.ResponseFacade
  296       public boolean isCommitted() {
  297   
  298           if (response == null) {
  299               throw new IllegalStateException(
  300                               sm.getString("responseFacade.nullResponse"));
  301           }
  302   
  303           return (response.isAppCommitted());
  304       }

Logo, a linha “return (response.isAppCommitted());” está retornando true.
Pois bem, olhando agora o método isAppCommitted() da classe org.apache.catalina.connector.Response:

///////////Classe org.apache.catalina.connector.Response
  326       /**
  327        * Application commit flag accessor.
  328        */
  329       public boolean isAppCommitted() {
  330           return (this.appCommitted || isCommitted() || isSuspended()
  331                   || ((getContentLength() > 0) 
  332                       && (getContentCount() >= getContentLength())));
  333       }

Aí danou-se tudo, pq já nem imagino o que de fato signitica esse “está ‘comitado’” que as classes usam.
Creio que só deixou a parada mais complicada…rs
Ou eu esteja correndo atrás do próprio rabo. hehe

Anyway, alguma dica??

Abç

bronx

Segundo esse post do StackOverflow, o java.lang.IllegalStateException é lançado quando a resposta já foi comitada.
Um response comitado é um response que, segundo o post, satisfaz ao menos uma das seguintes condições:

  • O header do response já foi definido;
  • Foi executado um forward() ou um include() anteriormente;
  • Mais de 2KB de dados foram gravados no response;
  • Ou menos de 2KB de dados foram escritos e o flush() foi executado.

Será que o proxy faz alguma dessas coisas antes de executar de fato o sendRedirect()???
Seria eu o único a passar por essa situação? =S

Abç

G

Bem complicado saber o que é esse erro apenas com o stacktrace. Realmente você está certo quando ao IllegalStateException.

Como é feito o redirect? Há algumas outras condições envolvidas?

Se nunca algum usuário reclamou isso, pode ser que esteja sendo feito dois redirects. Como o browser do cliente já muda a tela no primeiro redirect, ele não irá notar o segundo redirect, mas o log irá capturar a exception.

A melhor forma de conseguir achar o motivo do erro é colocar uns logs e ficar monitorando.

sergiolopes

90% das vezes isso indica que você já tinha escrito algo no Response e depois tentou dar um redirect.

Lucas_Cavalcanti

existem outras chamadas ao Result antes desse redirect pro login?

isso acontece no meio de um forward?

bronx

garcia-jj:
Bem complicado saber o que é esse erro apenas com o stacktrace. Realmente você está certo quando ao IllegalStateException.

Como é feito o redirect? Há algumas outras condições envolvidas?

Se nunca algum usuário reclamou isso, pode ser que esteja sendo feito dois redirects. Como o browser do cliente já muda a tela no primeiro redirect, ele não irá notar o segundo redirect, mas o log irá capturar a exception.

A melhor forma de conseguir achar o motivo do erro é colocar uns logs e ficar monitorando.

Garcia, o usuário reclamou sim. Aliás, foi graças a ele que descobri esse erro, pois isso só ocorre em produção, e de vez em quando.
Esse stack que postei foi o que tirei do log do server. Todas as ocorrências do IllegalStateException são sempre no mesmo trecho do código.

Olha só o método “logar”:

public void logar(DadosLogin dadosLogin, Senha senha) {
		
		if (this.usuarioCorrente.getUsuarioCorrente() != null)
			this.result.use(Results.logic()).redirectTo(MenuPrincipalController.class).inicio(); ////REDIRECT AQUI!!!
		
		dadosLogin.setSenha(senha.getValor());
		Usuario usuario = this.usuarioDao.getByDadosLogin(dadosLogin);
		
		if (usuario == null) {
			this.validator.add(new ValidationMessage(this.mensageiro.getMensagem("login.senha.invalidos"), "loginFalhou"));
		} else {
			if (!usuario.isAtivo()) {
				this.validator.add(new ValidationMessage(this.mensageiro.getMensagem("usuario.inativo"), "usuario.inativo"));
			} else {
				this.registraAcesso(usuario);
			}
		}
		this.validator.onErrorUse(Results.logic()).redirectTo(LoginController.class).login();//REDIRECT AQUI!!!
		
		this.result.use(Results.logic()).redirectTo(MenuPrincipalController.class).inicio();//REDIRECT AQUI!!!

	}

Como podem ver, há redirecionamentos em 3 pontos do método. Posso estar estrogonoficamente enganado, mas até onde sei, o redirect quebra totalmente o fluxo de execução do código. Logo, ao encontrar um redirect, ele pára a execução do método e executa o redirecionamento, o que não permitiria haver 2 redirecionamentos. Am I wrong?

Lucas_Cavalcanti

o result nunca pára o fluxo… só o validator.onErrorUse…

então o seu primeiro if deveria fazer o return:

if (this.usuarioCorrente.getUsuarioCorrente() != null) {
    this.result.use(Results.logic()).redirectTo(MenuPrincipalController.class).inicio();
    return;
}

ou ainda usar o validator:

if (this.usuarioCorrente.getUsuarioCorrente() != null) 
    validator.add(umaMensagem);
this.validator.onErrorRedirectTo(MenuPrincipalController.class).inicio();

PS: existem atalhos para o redirect:

result.redirectTo(...);
result.redirectTo(this).metodo(); //se for o mesmo controller
validator.onErrorRedirectTo(...);
Lucas_Cavalcanti

uma refatoração do seu método que funcionaria:

public void logar(DadosLogin dadosLogin, Senha senha) {  
      
    if (this.usuarioCorrente.getUsuarioCorrente() == null) {
       dadosLogin.setSenha(senha.getValor());  
       Usuario usuario = this.usuarioDao.getByDadosLogin(dadosLogin);  
      
       if (usuario == null) {  
           this.validator.add(new ValidationMessage(this.mensageiro.getMensagem("login.senha.invalidos"), "loginFalhou"));  
       } else {  
           if (!usuario.isAtivo()) {  
              this.validator.add(new ValidationMessage(this.mensageiro.getMensagem("usuario.inativo"), "usuario.inativo"));  
           } else {  
              this.registraAcesso(usuario); // XXX isso não deveria estar depois do validator.onErrorUse?
           }  
       }  
       this.validator.onErrorUse(Results.logic()).redirectTo(LoginController.class).login();//REDIRECT AQUI!!!  
    }
  
    this.result.use(Results.logic()).redirectTo(MenuPrincipalController.class).inicio();//REDIRECT AQUI!!!  
  
}
bronx

Lucas Cavalcanti:
o result nunca pára o fluxo… só o validator.onErrorUse…

então o seu primeiro if deveria fazer o return:

if (this.usuarioCorrente.getUsuarioCorrente() != null) {
    this.result.use(Results.logic()).redirectTo(MenuPrincipalController.class).inicio();
    return;
}

ou ainda usar o validator:

if (this.usuarioCorrente.getUsuarioCorrente() != null) 
    validator.add(umaMensagem);
this.validator.onErrorRedirectTo(MenuPrincipalController.class).inicio();

PS: existem atalhos para o redirect:

result.redirectTo(...); result.redirectTo(this).metodo(); //se for o mesmo controller validator.onErrorRedirectTo(...);

Saquei.

Simulei a situação onde a condição fosse satisfeita, ou seja, ele caiu dentro do if, depois executou o outro redirect eeeee… BINGO!

Jan 13, 2011 2:11:02 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet default threw exception
br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: java.lang.IllegalStateException
	at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:86)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:69)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:90)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:42)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.util.hibernate.HibernateTransactionInterceptor.intercept(HibernateTransactionInterceptor.java:45)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:44)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:81)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:70)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56)
	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:230)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at br.com.locaweb.tomcat.LocaWebValve.invoke(LocaWebValve.java:134)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
	at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
	at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:283)
	at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:767)
	at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:697)
	at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:889)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:686)
	at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.IllegalStateException
	at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)
	at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:126)
	at br.com.caelum.vraptor.http.VRaptorResponse.sendRedirect(VRaptorResponse.java:46)
	at br.com.caelum.vraptor.view.DefaultLogicResult$2.intercept(DefaultLogicResult.java:124)
	at br.com.caelum.vraptor.proxy.AbstractCglibProxifier$2.intercept(AbstractCglibProxifier.java:56)
	at br.com.scv.controller.MenuPrincipalController$$EnhancerByCGLIB$$8863f26e.inicio(<generated>)
	at br.com.scv.controller.LoginController.logar(LoginController.java:93)
	at sun.reflect.GeneratedMethodAccessor253.invoke(Unknown Source)
	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:57)
	... 51 more

A questão era conceitual mesmo. Achava que todo e qualquer redirect resultava no “halt” do método em questão!

Enfim! Valeu Lucas, Sergio e Garcia! Bora tomar umas qqr dia desses! hehe

PS: Lucas, eu conheço os atalhos. É que essa classe foi escrita numa era onde eles sequer imaginavam existir! hehehe Nota-se a necessidade de refactor justamente naquele primeiro if, que valida se o cara já tá logado.
Anyway, valeu!!

Criado 10 de janeiro de 2011
Ultima resposta 13 de jan. de 2011
Respostas 10
Participantes 4