Mostrando postagens com marcador servlet. Mostrar todas as postagens
Mostrando postagens com marcador servlet. Mostrar todas as postagens

terça-feira, 10 de abril de 2007

Verificando o funcionamento de SingleThreadModel

SingleThreadModel é do mau. Não é recomendável que se use de maneira alguma, é até uma interface marcada como deprecated. Mas mesmo assim, por algum motivo obscuro ela cai na prova do SCWCD. Para verificar o seu funcionamento criei dois servlets, um sem implementar a famigerada interface e o outro implementando.

Servlet não implementando SingleThreadModel:
public class TesteSemSingleThreadModel extends HttpServlet
{
public static int instancias = 0;

public void init()
{
instancias++;
}

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
response.getWriter().print("Instancias: " + instancias);
}
}

Servlet implementando SingleThreadModel:
public class TesteComSingleThreadModel extends HttpServlet implements SingleThreadModel
{
public static int instancias = 0;

public void init()
{
instancias++;
}

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
response.getWriter().print("Instancias: " + instancias);
}
}

Como resultado pude perceber que o primeiro servlet, que não implementa a interface discutida, quando chamado exibe o texto "Instancias: 1" indicando que o método init() foi chamado apenas uma vez. Já o segundo servlet que implementa a SingleThreadModel, quando chamado exibe o texto "Instancias: 2". Ou seja, duas instancias do servlet foram criadas, uma para cada thread do Tomcat, container que estou utilizando.

segunda-feira, 9 de abril de 2007

No forward QueryString pode ser capturada de maneira diferente

Quando um servlet chama repassa a requisição para outro, utilizando o método forward do RequestDispatcher, este outro servlet pode capturar a QueryString do primeiro tanto utilizando o método getQueryString() de HttpServletRequest como utilizando o attributo "javax.servlet.forward.query_string" da requisição.

Segue o servlet que repassa a requisição para o próximo
public class MeuServlet1 extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
request.getRequestDispatcher("/MeuServlet2").forward(request,response);
}
}

Agora o servlet que recebe a requisição:
public class MeuServlet2 extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter p = response.getWriter();
p.print("Query String1: " + request.getQueryString() );
p.print("Query String2: " + request.getAttribute("javax.servlet.forward.query_string") );
}
}

Informação inutil para quem está desenvolvendo, mas importante para quem assim como eu estuda para tirar a SCWCD.

quarta-feira, 4 de abril de 2007

IllegalStateException quando utilizado o forward de RequestDispatcher

Quando uma resposta já tiver sido enviada do servidor de aplicações para o cliente, o método forward da interface RequestDispatcher não pode ser utilizado, pois ele não funciona e gera um IllegalStateException.

Criei um código para testar em quais momentos a resposta é passada ao usuário para descobrir quando é que poderíamos obter essa exceção. Veja:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
String param = request.getParameter("tipo");
if( param==null || param.length() == 0 )
{
response.getWriter().print("Informe o parametro tipo com os valores: ");
response.getWriter().print(" print, flush, stream, close, header ou cookie");
}
else
{
if( "print".equals(param) )
{
response.getWriter().print("alguma coisa");
}
else if( "flush".equals(param) )
{
response.getWriter().print("alguma coisa");
response.getWriter().flush();
}
else if( "stream".equals(param) )
{
ServletOutputStream output = response.getOutputStream();
}
else if( "close".equals(param) )
{
response.getWriter().print("alguma coisa");
response.getWriter().close();
}
else if( "header".equals(param) )
{
response.addHeader("Pragma","no-cache");
}
else if( "cookie".equals(param) )
{
Cookie c = new Cookie("nome","valor");
response.addCookie(c);
}

try
{
request.getRequestDispatcher("/meu.jsp").forward(request,response);
}
catch(IllegalStateException e)
{
e.printStackTrace();
}
}
}
Com isso descobri que a exceção é gerada quando os métodos flush e close do PrintWriter, que é criado pelo HttpServletResponse, são chamados, e quando o método getOutputStream do HttpServletResponse é invocado. Isso é claro, se após chamá-los for executado um forward.

Verifiquei também que se o forward for executado antes, somente a chamada a getOutputStream gera a exception. No tomcat ele dá a seguinte mensagem: getWriter() has already been called for this response.

Método forward de RequestDispatcher prevê algumas exceções

Sempre que utilizar o método forward da interface RequestDispacther é preciso tratar exceções ServletException e IOException. Utilizando uma IDE como o eclipse a gente nunca se preocupa com isso, mas para quem está estudando pro SCWCD, isso é importantíssimo.

Primeiro é preciso importar as classes:
import javax.servlet.ServletException;
import java.io.IOException;
Depois tratar ou capturando a exceção:

try
{
request.getRequestDispatcher("/pagina.jsp").forward(request,response);
}
catch(IOException e)
{
log(e.getMessage());
}

catch(ServletException e)
{
log(e.getMessage());
}
Ou reenviando ela:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
request.getRequestDispatcher("/pagina.jsp").forward(request,response);
}