Gente, bom dia.
Eu estou com a seguinte exception quando eu faço um redirect. Mas o problema é que acontece somente em 1 método.
Os outros estão fazendo redirect normalmente…
Gostaria de entender porquê que isso acontece.
Aqui está a StackTrace:
09/04/2012 07:59:18 org.apache.catalina.core.StandardContextValve throwable
AVISO: Exception Processing ErrorPage[exceptionType=java.lang.Exception, location=/erro.jsp]
ClientAbortException: java.net.SocketException: Connection reset by peer: socket write error
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:333)
at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:299)
at org.apache.catalina.connector.Response.flushBuffer(Response.java:560)
at org.apache.catalina.core.StandardContextValve.throwable(StandardContextValve.java:404)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:204)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:151)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:269)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(Unknown Source)
at java.net.SocketOutputStream.write(Unknown Source)
at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:216)
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:437)
at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:119)
at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:721)
at org.apache.coyote.Response.action(Response.java:170)
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:328)
... 16 more
isso acontece sempre nesse método?
Sempre. O método é responsável por salvar um determinado registro e depois dá um redirect para uma tela que lista esses registros.
Eu percebi que o erro acontece e o VRaptor manda ele refazer a requisição, ele volta certinho, tenta inserir e dá erro pois já foi inserido.
Quando dá o erro, ele faz um redirect para outra tela, o formulário. E este segundo redirect funciona direitinho.
então tão acontecendo 2 redirects, certo?
tipo dá erro ao commit da transação e daí vc redireciona pra uma página de erro?
Não, primeiro ele insere o registro no banco e manda uma mensagem na tela informando que foi inserido e depois dá um redirect, ai é lançado o ClientAbortException.
Depois o interceptor do VRaptor captura esse erro e chama o método denovo. Passando os mesmos parametros novamente.
Nesse momento, tenta fazer o insert novamente, mas por existir campos unique, dá uma HibernateException. Quando acontece uma HibernateException, eu mando uma mensagem na view e dou um redirect para o formulário.
Esse segundo redirect não lança o ClientAbortException. Só o primeiro.
public void associar(SellerDeepSea sellerDeepSea,
CustomerPadrao customerPadrao, AccountGroup accountGroup) {
try {
RelCusSelAcc obj = new RelCusSelAcc();
obj.setAccountGroup(accountGroup);
obj.setCustomerPadrao(customerPadrao);
obj.setSellerDeepSea(sellerDeepSea);
obj.setSituacao(Situacao.ATIVO);
sellerDeepSeaDAO.saveRelacionamento(obj); // aqui não dá erro na primeira vez
service.modal("sucesso", "objAssociado",
".dataTables_filter input:text");
result.redirectTo(this).listCustomer(sellerDeepSea.getCodigo()); // aqui é lançado o ClientAbortException.
} catch (HibernateException e) {
// ClientAbortException não é tratado nesse catch
service.modal("erro", "objNaoAssociado", "#accountGroup");
result.redirectTo(this).associacoes(sellerDeepSea.getCodigo());// na segunda vez que fizer a requisição, vai dar HibernateException e vai executar esse redirect normalmente.
}
}
Outra coisa que eu percebi é que se eu inserir um catch para ClientAbortException e simplesmente não fazer nada, as requisições ficam malucas.
esse service.modal tenta escrever algo no response?
o método modal insere dados pelo result.include…
Ele nunca deu problema… Mas nunca se sabe, né.
Aqui está o codigo dele.
[code]public void modal(String titulo, String mensagem, String onClickFocus) {
if (this.bundle != null) {
titulo = this.bundle.getString(titulo);
mensagem = this.bundle.getString(mensagem);
}
if (onClickFocus != null && onClickFocus != "") {
onClickFocus = "$('" + onClickFocus + "').focus();";
this.result.include("onClickFocus", onClickFocus);
}
this.result.include("mensagemModal", mensagem);
this.result.include("tituloModal", titulo);
this.result.include("buttonFocus", "buttonConfirmar");
this.result.include("modal", "modalOK");
}[/code]
estranho… o client abort é qdo o browser desiste da requisição…
não tem mais nada que faça operações com o response? tipo um interceptor?
Tem sim. Isso tem a ver com o browser? Esse é um sistema corporativo e intranet que só pode ser acessado por IE8.
[code]@Intercepts(after = FuncionalidadesInterceptor.class)
public class SetFuncionalidadesInterceptor implements Interceptor {
private final UserWeb userWeb;
private final Result result;
public SetFuncionalidadesInterceptor(UserWeb userWeb, Result result) {
this.userWeb = userWeb;
this.result = result;
}
@Override
public void intercept(InterceptorStack stack, ResourceMethod method,
Object resourceInstance) throws InterceptionException {
for (TipoFuncionalidade funcionalidade : userWeb
.getFuncionalidadeList()) {
result.include(("FUNC_" + funcionalidade.name()), true);
}
stack.next(method, resourceInstance);
}
@Override
public boolean accepts(ResourceMethod method) {
return (this.userWeb.getLogado());
}
}[/code]
[code]@Intercepts(after = ParametersInstantiatorInterceptor.class)
public class NoCacheInterceptor implements Interceptor {
private final HttpServletResponse response;
public NoCacheInterceptor(HttpServletResponse response) {
this.response = response;
}
@Override
public void intercept(InterceptorStack stack, ResourceMethod method,
Object resourceInstance) throws InterceptionException {
// set the expires to past
response.setHeader("Expires", "Wed, 31 Dec 1969 21:00:00 GMT");
// no-cache headers for HTTP/1.1
response.setHeader("Cache-Control",
"no-store, no-cache, must-revalidate");
// no-cache headers for HTTP/1.1 (IE)
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
// no-cache headers for HTTP/1.0
response.setHeader("Pragma", "no-cache");
stack.next(method, resourceInstance);
}
@Override
public boolean accepts(ResourceMethod method) {
return true;
}
}[/code]
Se for por causa do interceptor, tem grandes chances de ser pelo NoCacheInterceptor… Mas eles estão ai há muito tempo. E em todas as outras requisições tudo funciona normalmente.
qdo o client abort acontece não dá o erro do hibernate, certo?
a requisição é direto pro método associar?
a requisição chega a voltar pro browser?
Não dá, tanto que se eu voltar para a tela de listagem, o novo registro aparece la.
Quando eu envio a requisição, ela é direto sim. Assim como quando o VRaptor refaz ela.
A requisição só volta pro browser depois que o VRaptor refaz a requisição e dá HException…
o vraptor refaz a requisição? ou é a aplicação que faz isso?
é o VRaptor. Ele cai nesse finally aqui.
public <T> T provideForRequest(RequestInfo request, Execution<T> execution) {
VRaptorRequestHolder.setRequestForCurrentThread(request);
REQUEST.start();
try {
return execution.insideRequest(container);
} finally {
REQUEST.stop();
VRaptorRequestHolder.resetRequestForCurrentThread();
}
}
mas esse código não refaz a requisição… o REQUEST.stop(); só e o cara que finaliza o escopo de request.
VRaptorRequestHolder.resetRequestForCurrentThread();
Esse método faz o que? Pelo nome eu pensei que ele refizesse o request. Pois logo à frente (depois de muitos f6) ele volta para o método associar.
ele limpa um thread local (feio, mas necessário) só isso.
Então quem refaz a requisição? Pois quando ele sai do método, ele passa por tudo isso e depois volta para o método…
será que não é a própria aplicação fazendo isso? será que ela não tá repetindo a requisição?
vc consegue fazer a requisição em outro browser, ou, melhor ainda, sem browser? (via linha de comando ou usando o poster do firefox)
Só pode ser o browser, testei no firefox e ele funciona lindo e bonito.
Agora é pior do que eu imaginava.
Então, pela exception que está dando, significa que o browser cortou a sessão no meio… Mas por que? Como é que eu arrumo isso? Agora eu fiquei completamente perdido…