quarta-feira, 25 de abril de 2007

Como criar funções em sua taglib

Caso você tenha necessidade de uma função que não existe na JSTL, você pode criar facilmente sua própria função. Nesse mini tutorial explicarei como fazer isto. Faremos uma função que retira os simbolos de maior e de menor (<>) dos textos para impedir que tags htmls sejam inseridas numa página. A primeira coisa a se fazer é criar uma classe com um método estático com essa funcionalidade. Veja:
package meupacote;

public class MinhaClasse
{
public static String escapeHtml(String html)
{
String texto = null;
if( html != null )
{
texto = html.replaceAll("<", "& lt;");
texto = texto.replaceAll(">", "& gt;");
}
return texto;
}
}
Como podemos ver, o método escapeHtml recebe um html e substitui todas as ocorrências de < > pelo seu código equivalente em html. O segundo passo é definir no seu arquivo tld essa function, inserindo a tag function e suas sub-tags de configuração. Veja:

<function>
<description>
Substitui tags simbolos de maior e maior pelo seu codigo html
</description>
<name>escapeHtml</name>
<function-class>meupacote.MinhaClasse</function-class>
<function-signature>boolean escapeHtml(java.lang.String)</function-signature>
</function>
As tags mais importantes da configuração da função são "name", que indica por qual nome ela será referenciada no jsp, "function-class", que indica qual classe possui o método equivalente à função e "funtion-signature", que indica qual o método responderá pelas ações da função.

Tendo isso, basta utilizar essa função no seu jsp, importando sua taglib e chamando a função no formato prefixo:nomefuncao(parametros). Veja o exemplo:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="mt" uri="http://programandosemcafeina.blogspot.com/jsp/taglib/mt" %>

<h1><c:out value="${mt:escapeHtml(materia.titulo)}" /></h1>
<p><c:out value="${mt:escapeHtml(materia.texto)}" /></p>
É claro que por eu usar a tag c:out não seria necessária a função escapeHtml, pois essa tag já faz a conversão que implementamos (e muitas outras). Contudo existem situações em que ela seria necessária. Um exemplo é se utilizarmos a Json Taglib. Essa taglib não tem a opção de escapar o html, para ela então faz-se necessário o uso de uma função como a que fizemos no exemplo.

segunda-feira, 23 de abril de 2007

Resumo do Sun Tech Days de 2007

Segue o resumão de todos os dias do Sun Tech Days de 2007. As fotos e vídeos irei postar durante a semana.

Resumo do Sun Tech Days do dia 19/04/2007
Resumo do Sun Tech Days do dia 20/04/2007

Resumo do Sun Tech Days do dia 20/04/2007

Aqui estão as minhas impressões e o que aprendi no segundo dia do Sun Tech Days de São Paulo:
Demorei um pouco pra postar mais foi :)

WEB 2.0 com Ajax no Sun Tech Days

Essa palestra não trouxe muitas informações novas, era mais para iniciantes na área de ajax, explicando como funcionam as chamadas assincronas utilizando o objeto XMLHttpRequest e dando alguns exemplos bem manjados. Uma coisa apresentada que eu não conhecia é o JMaki Widget. Com essa ferramento no NetBeans, rapidamente a palestrante fez uma página com um menu de imagens de cidades, utilizando aquele efeito que o menu do OS-X tem, que ao clicar em uma delas era exibida a localização da cidade, utilizando Yahoo Maps. Só com Widgets. É uma boa dar uma pesquisada nessa ferramenta.

Aplicações BPEL e SOA com Oracle no Sun Tech Days

Com essa palestra finalmente aprendi o que é BPEL e para que serve. Relutei muito em ler sobre o assunto, mas não teve jeito :) Segundo a palestra utilizamos o BPEL quando precisamos chamar vários webservices em sequências.

Achei muito interessante, mas a idéia de programar via XML não me agrada. Estruturas condicionais e loops num XML são coisas que nunca me agradarão. Contudo, o fato de ser XML torna a customização de um workflow mais fácil de ser manejado por um programa, como o da Oracle que foi exibido na palestra.

Algumas tags de atividades que foram mostradas são <receive> que recebe a requisição de um cliente, o <reply> que retorna a requisição para o cliente e o <invoke> que chama um webservice. E algumas tags de estrutura que foram mostradas são <sequence> que faz com que as atividades em seu interior sejam executadas em sequencia, <flow> que faz com que as atividades em seu interior sejam executadas em paralelo e <switch> que tem a mesma responsabilidade de um switch programático.

Outra coisa interessante mostrada nessa palestra foi como é formado um arquivo WSDL. Primeiro os tipos de dados, depois as mensagens, os ports referenciando as mensagens, os bindings e finalmente o service.

Linguagens de script no Java no Sun Tech Days

Palestra muito interessante mostrando a capacidade do Java 6 de executar linguagens de script. Basicamente existem duas formas de se executar uma liguagem de script no Java, por dentro de uma classe ou utilizando o executavel jrunscript.

Dentro de uma classe é preciso pegar o ScriptEngine utilizando o ScriptEngineManager. O ScriptEngine possui um método eval(String ou Reader) que executa um script apartir de uma String ou apartir de um arquivo utilizando um Reader. Para invocar funções utiliza-se o método invokeFunction(String), e nessa chamada pode-se indicar os parâmetros da função pois é um método que utiliza varargs.

Outra coisa legal é o método put que serve para colocar objetos Java dentro do script. As alterações ocorridas neste objeto dentro do script são refletidas fora do script. Também foi mostrado um exemplo de javascript importanto classes Java, com a função importPackage.

Muitos se perguntam se esse suporte a linguagens de script é mesmo necessário e o palestrante deu uma boa idéia do porque é sim importante. Primeiro porque a idéia é que o Java se separe de sua VM, de forma que esta VM possa rodar não só em diversas plataformas como também diversas linguagens. Segundo porque poder executar script apartir de classes Java é muito bom para customização de sistemas, principalmente na área financeira.

Sobre JSF no Sun Tech Days

Nessa palestra falou-se sobre as qualidades e defeitos do JSF, motivos para utilizá-lo, e sobre o futuro deste framework. Ao final foram feitos alguns rápidos exemplos utilizando o Visual Web Pack em conjunto com o Sun Java Creator.

Interessante foi saber que no futuro o JSTL e o JSF estarão no mesmo pacote. Ou seja, a Sun está fazendo de tudo para que o JSF enfim ganhe mercado. Hoje o JSTL é utilizado em conjunto com outros frameworks, mas se o JSF vier junto com o JSTL, será estranho utilizar outro que não o JSF.

Outra ponto citado que eu já havia lido a respeito é que com o JSF é possivel que uma mesma página gere resultado em vários formatos, não só HTML. Basta utilizar algum RenderKit diferente do HTMLRenderKit. Pena que não foi mostrado nenhum exemplo, esse é mais um assunto que merece que eu faça uma boa pesquisa.

Ao final a palestrante mostrou dois exemplos, um parecido com o da palestra do ADF da Oracle, com a diferença de que o Sun Java Creator com o Visual Web Pack funcionou muito melhor que o JDeveloper em termos de desempenho (é bom lembrar que o JDeveloper exibido era uma versão pré-alfa).

O outro era uma integração com o PayPal que gerou um erro na aplicação. Quando isso ocorreu a palestrante ficou tão constrangida que tivemos dois minutos de silêncio absoluto. Felizmente o erro foi corrigido e ela enfim conseguiu exibir o exemplo pra nós.

sexta-feira, 20 de abril de 2007

Ferramentas Oracle no Sun Tech Days

Nessa palestra falou-se sobre algumas ferramentas da Oracle para desenvolvimento web como o ADF, framework da Oracle baseado em JSF e EJB3. O exemplo que o palestrante fez com o JDeveloper ficou muito bonito, um grid utilizando um componente JSF deste IDE, que ao ser renderizado é exibido com opções de redimensionar colunas e ordenar por elas. Mão na roda não ter que procurar e adaptar esses scripts. Quem já fez um grid desses, cheios de firulas web 2.0, sabe a chatice que é. Contudo, a apresentação deixou uma má impressão, pois o JDeveloper demorou muito para carregar. Sem graça o palestrante explicou que isso ocorria porque era versão pré-alfa. Amador?

Abertura do segundo dia do Sun Tech Days

Novamente escrevo sem acentos pois no connection point do Sun Tech Days nao tem como utilizar caracteres especiais.

A abertura desse segundo dia foi muito macante. O palestrante parecia mais um pastor de igreja evangelica do que alguem da area de tecnologia. Objetividade zero. Foi mais de meia hora repetindo o mesmo refrao de comunidade. Esse tipo de discurso serve mais para pessoas da area de humanas.

Depois tivemos uma palestra sobre algumas ferramentas da Oracle, que descreverei mais tarde.

O bom mesmo, foi ao final da abertura, que teve um divertido concurso habilidades no palco. Desenvolvedores e arquitetos subiam para cantar, dancar e especialmente pagar mico. Destaque para os vencedores do concurso, uma menina que veio preparadissima para dancar danca do ventre e um rapaz, mais troncho nunca vi, que tambem dancou danca do ventre, sem camisa, com as banhas balancando. Eu ri muito.

Essas palhacadas eu filmei. Logo logo colocarei os videos no Youtube e entao eu posto aqui no Programando sem cafeina.

Resumo do Sun Tech Days do dia 19/04/2007

Aqui estão as minhas impressões e o que aprendi no primeiro dia do Sun Tech Days de São Paulo:

Agora vou dormir porque amanhã tem mais, se eu conseguir vaga no connection point eu posto mais durante o dia.

quinta-feira, 19 de abril de 2007

EJB 3 e JPA no Sun Tech Days

A palestrante explicou como funciona o mapeamento objeto-relacional do JPA por anotações de relacoes ManyToOne e ManyToMany, e como mapear herança utilizando uma só tabela. Para diferenciar se um objeto é de uma subclasse ou de outra utiliza-se a anotação @DiscriminatorColumnName e @DiscriminatorValue. Essa foi a melhor palestra do dia pois explicou do ínicio ao fim o mapeamento, como funciona o EntityUnit, como funciona o EntityManager, mostrou o ciclo de vida de uma entidade e deu ótimas dicas para não termos problemas no desenvolvimento utilizando JPA. Mais tarde quando eu baixar os power points repassarei essas dicas. Agora eu vou aproveitar o cocktail :)

Palestra de JAX-WS e WSIT no Sun Tech Days

Não consegui entender muito sobre esta palestra porque o palestrante falava rápido demais e a tradução simultânea, como mencionei antes, é um desastre, e além disso, nessa palestra a tradução estava especialmente ruim.

O que achei interessante, mas não entendi como funciona é o método de webservice assíncrono, assim que puder pesquisarei sobre o assunto. O palestrante fez também um WebService simples utilizando o JavaSE 6, com a anotacao @WebService e gerando os stubs com o comando wsimport. É incrivel como WebService fica mais facil com o JavaSE 6.

VMWare no Sun Tech Days

Nao gostei muito da palestra sobre Virtual Desktop da VMWare, isso porque infra-estrutura nao eh a minha praia, e as coisas que aprendi nao me serao uteis no trabalho, apenas como curiosidade. Gostei da ideia de economia de energia que a utilizacao de maquinas virtuais pode proporcionar. E a ideia de Remotion, no qual um servidor virtual pode ser transferido de um servidor fisico para outro. Isso eh muito util. Uma sugestao que o palestrante deu eh utilizar isso para transferir ambientes totalmente testados para producao, sem nova instalacao.

Palestra sobre JavaSE 6 no Sun Tech Days

Tivemos uma palestra mostrando as novas funcionalidades do JavaSE 6. O que foi mais interessante foram as alterações no Swing e no AWT. Dentre essas novas funções temos a nova classe TrayIcon que permite colocar um programa na bandeja do Sistema Operacional (Ali, ao lado do relógio), uma forma exibir uma tela de splash antes mesmo de carregar a JVM, e a classe Desktop que permite abrir sistemas nativos.

Outra nova funcionalidade que foi citada e que parece muito boa é a SwingWorker, que serviria para facilitar o trabalho multi-thread em aplicações Swing, pena que não mostraram nem mesmo um exemplo dela. Qualquer dia desses eu dou uma pesquisada sobre ela para colocar aqui.

No JavaSE6 também foram introduzidos novos executáveis para monitoração da aplicação, como é o caso do jconsole. Outro destaque é pela nova forma de criação de WebServices que dispensa a criacao do WSDL, bastando anotar a classe que irá prover o servico com @WebService. O proprio JavaSE levantaria um mini-servidor http para oferecer este servico, bastanto publicar o endpoint com Endpoint.publish.

Segundo o palestrante a migracao de JavaSE 5 para JavaSE 6 nao é custo algum pois nao há alteracao de sintaxe. Portanto é extremamente recomendável a migração devido às melhorias de performance.

Demos do Sun Tech Days

Foram exibidas duas demonstracões de desenvolvimento rápido com o NetBeans. Nao sou fã dessa IDE, mas tenho que tirar o chapéu, foram ótimas demonstrações. Primeiro fez-se um menu SVG para JavaME e depois uma demonstração de uma aplicacao com o Matise. Ambos mostraram como é rápido o desenvolvimento no NetBeans. Acredito que no dia em que a Sun investir no aperfeiçoamento do editor desta IDE, o NetBeans finalmente poderá barrar o Eclipse. Enquanto isso continuo fiel ao programa que esconde o sol.

Outra coisa legal foi a exibição do SunSpot, uma espécie de luva que faz com que tenhamos um efeito similar ao do filme Minority Report misturado com o LookInGlass, o destop 3D feito em Java. Não funcionou perfeitamente, teve um momento em que a menina que apresentava teve que repetir o movimento umas duas vezes para girar umas janelas, mesmo assim foi lindo de se ver. Sinto que o futuro dos desktops será emocionante.

Abertura do Sun Tech Days

Estou aqui no Sun Tech Days em São Paulo, os próximos textos que eu postar aqui não terão acento. Estou numa máquina do connecting point que aparentemente não possui suporte a caracteres especiais (Atualizado: Agora no hotel estou corrigindo os acentos). Já adiantando, a coisa mais engraçada do evento é o serviço de tradução simultânea. Os tradutores não tem nenhuma familiaridade com os termos de informática, soltando perólas engraçadíssimas.

Logo na primeira palestra tivemos uma bela parábola sobre ciclo de vida de software. Uma comparação mostrando que assim como é mais produtivo para os cientistas fazerem esperiências em animais menores, como ratos e insetos, do que com animais maiores, como um elefante por exemplo, também é melhor para programadores trabalharem no desenvolvimento de softwares com ciclos de vidas mais rápidos e de contínuo feedback.

Falou-se muito sobre a separação entre VM e a linguagem Java, mostrando qual o objetivo da Sun no suporte a linguagens de script. O que ocorre hoje é que essas linguagens possuem cada uma a sua própria VM. A idéia da Sun é que no futuro todas rodem em uma mesma VM, tornado-as portáveis para diversas plataformas. Inicialmente isso se dará com uma camada de biblioteca java, mas no futuro a idéia é tirar essa camada. O Java 6 já possui suporte a javascript.

terça-feira, 17 de abril de 2007

Caracteres especiais representados em Unicode

Para evitar problemas com encoding de caracteres especiais é bom utilizar em suas classes Java código unicode ao invés de letras acentuadas. Abaixo relaciono uma tabela de alguns dos caracteres especiais que mais usamos no dia a dia com seu cógigo unicode:
á = \u00e1
à = \u00e0
â = \u00e2
ã = \u00e3
ä = \u00e4
Á = \u00c1
À = \u00c0
 = \u00c2
à = \u00c3
Ä = \u00c4
é = \u00e9
è = \u00e8
ê = \u00ea
ê = \u00ea
É = \u00c9
È = \u00c8
Ê = \u00ca
Ë = \u00cb
í = \u00ed
ì = \u00ec
î = \u00ee
ï = \u00ef
Í = \u00cd
Ì = \u00cc
Î = \u00ce
Ï = \u00cf
ó = \u00f3
ò = \u00f2
ô = \u00f4
õ = \u00f5
ö = \u00f6
Ó = \u00d3
Ò = \u00d2
Ô = \u00d4
Õ = \u00d5
Ö = \u00d6
ú = \u00fa
ù = \u00f9
û = \u00fb
ü = \u00fc
Ú = \u00da
Ù = \u00d9
Û = \u00db
ç = \u00e7
Ç = \u00c7
ñ = \u00f1
Ñ = \u00d1
& = \u0026
' = \u0027
Para colocar o código Unicode em uma String basta substituir o caracter pelo código. Exemplo: String s = "Programando sem cafe\u00edna";

O código do método que usei para gerar essa tabela está abaixo:
public static String geraCodigoUnicode(char letra) {
String hexa = Integer.toHexString( (int)letra );

String prefix;
if( hexa.length() == 1 ) {
prefix = "\\u000";
} else if( hexa.length() == 2 ) {
prefix = "\\u00";
} else if( hexa.length() == 3 ) {
prefix = "\\u0";
} else {
prefix = "\\u";
}

return prefix + hexa;
}

segunda-feira, 16 de abril de 2007

Pra que serve e como funciona o ServletRequestAttributeListener

O ServletRequestAttributeListener é uma interface que serve para monitorar os atributos adicionados, alterados e removidos de uma requisição. Sempre que se adiciona um atributo no objeto ServletRequest, o método attributeAdded do listener que implementa essa interface é chamado. Sempre que se substitui um atributo do objeto ServletRequest, o método attributeReplaced do listener que implementa essa interface é chamado. E finalmente, sempre que se remove um atributo do objeto ServletRequest o método attributeRemoved é chamado.

Veja abaixo o exemplo de uma classe que implementa esse listener para exibir o nome e o valor do parâmetro que foi adicionado, alterado e removido:
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.http.HttpServletRequest;

public class MeuServletRequestAttributeListener implements ServletRequestAttributeListener
{
public void attributeAdded(ServletRequestAttributeEvent e)
{
System.out.println("Atributo adicionado -> nome: "
+ e.getName() + ", valor: " + e.getValue() );
}

public void attributeRemoved(ServletRequestAttributeEvent e)
{
System.out.println("Atributo removido -> nome: "
+ e.getName() + ", valor: " + e.getValue() );
}

public void attributeReplaced(ServletRequestAttributeEvent e)
{
System.out.println("Atributo alterado -> nome: "
+ e.getName() + ", valorAntigo: " + e.getValue() );
}
}

Para testar esse listener criei ainda um Servlet mapeado com o endereço /TesteAtributoRequest.do. Este Servlet faz forward para si mesmo decrementando o atributo "numero" que é guardado na requisição. Veja como fica o código:
public void doGet(HttpServletRequest request, HttpServletResponse response) 
throws IOException, ServletException
{
int numero;

if( request.getAttribute("numero") != null )
{
numero = ( (Integer)request.getAttribute("numero") ).intValue();
numero--;
}
else
{
try
{
numero = Integer.parseInt( request.getParameter("numero") );
}
catch(NumberFormatException e)
{
numero = 3;
}
}

if( numero <= 0 )
{
request.removeAttribute("numero");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("Acaboooou");
}
else
{
request.setAttribute("numero", new Integer(numero));
request.getRequestDispatcher( "/TesteAtributoRequest.do" ).forward(request,response);
}
}

Ao executá-lo mandando o parâmetro "numero" com valor igual a 5 por exemplo, o listener configurado irá exibir a seguinte saída:

Atributo adicionado -> nome: numero, valor: 5
Atributo alterado -> nome: numero, valorAntigo: 5
Atributo alterado -> nome: numero, valorAntigo: 4
Atributo alterado -> nome: numero, valorAntigo: 3
Atributo alterado -> nome: numero, valorAntigo: 2
Atributo removido -> nome: numero, valor: 1

Pra que serve e como funciona o ServletRequestListener

O ServletRequestListener serve para ser notificado quando uma aplicação recebe uma requisição e quando esta requisição é destruída. Nomea-se no caso uma requisição como um objeto ServletRequest. Assim que o objeto ServletRequest é inicializado o método requestInitialized do listener que implementa a interface ServletRequestListener é chamado. Quando o objeto ServletRequest é destruído, o método requestDestroyed é chamado.

Veja um exemplo de um listener que implementa ServletRequestListener abaixo:
import javax.servlet.ServletRequestListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.http.HttpServletRequest;

public class MeuServletRequestListener implements ServletRequestListener
{
public void requestInitialized(ServletRequestEvent e)
{
HttpServletRequest r = (HttpServletRequest)e.getServletRequest();
System.out.println("Requisicao inicializada: " +
r.getRequestURI() );
}

public void requestDestroyed(ServletRequestEvent e)
{
HttpServletRequest r = (HttpServletRequest)e.getServletRequest();
System.out.println("Requisicao finalizada: " +
r.getRequestURI() );
}
}

No caso, o que o listener faz é escrever na saída padrão a URI requisitada quando uma nova requisição chega à aplicação e quando a requisição é finalizada. É importante notar que mesmo quando é feito uma requisição cujo resultado é um 404, o objeto de requisição é criado e em consequência os métodos do listener são chamados.

quarta-feira, 11 de abril de 2007

Pra que serve e como funciona o ServletContextAttributeListener?

O ServletContextAttributeListener é um listener que recebe sinais quando um atributo é adicionado, removido ou alterado no contexto. Para quem não sabe, um atributo de contexto é válido para todos os servlets, threads e sessões de uma aplicação. Para testar seu funcionamento criei uma classe implementando a interface ServletContextAttributeListener e um servlet para adicionar, remover e alterar atributos do contexto.

Segue o código do listener:
package meupacote.listeners;

import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextAttributeEvent;

public class MeuServletContextAttributeListener implements ServletContextAttributeListener
{
public void attributeAdded(ServletContextAttributeEvent e)
{
System.out.println("Atributo adicionado: nome=" +
e.getName() + ", valor=" + e.getValue()
);
}

public void attributeRemoved(ServletContextAttributeEvent e)
{
System.out.println("Atributo removido: nome=" +
e.getName() + ", valor=" + e.getValue()
);
}

public void attributeReplaced(ServletContextAttributeEvent e)
{
System.out.println("Atributo alterado: nome=" +
e.getName() + ", valorAntigo=" + e.getValue()
);
}
}
Veja que para implementar esse listener é preciso sobrescrever os métodos attributeAdded, que é chamado quando um atributo é adicionado, attributeRemoved, que é chamado quando um atributo é removido e attributeReplaced que é chamado quando um atributo é alterado.

O evento que esses métodos recebem possue dois métodos: getName e getValue, eles servem para pegar o nome e o valor do atributo manejado na ação. É preciso observar que no attributeReplaced, o getValue do evento retorna o valor anterior ao que foi alterado.

Agora veja o código do servlet que inclui, altera e remove atributos do contexto:
public class MudaAtributoContexto extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
{
String acao = request.getParameter("acao");
String nome = request.getParameter("nome");
String valor = request.getParameter("valor");

response.setContentType("text/html");
PrintWriter out = response.getWriter();

if( nome!=null )
{
if( "remover".equals(acao) )
{
getServletContext().removeAttribute(nome);
out.print("Removido: " + nome);
}
else
{
getServletContext().setAttribute(nome, valor);
out.print("Setado: " + nome + " = " + valor);
}
}

StringBuilder s = new StringBuilder("<form><b>Incluir: </b>")
.append(" nome: <input name=\"nome\"/>")
.append(" valor: <input name=\"valor\"/>")
.append(" <input type=\"submit\"/>")
.append("</form><hr />");

Enumeration e = getServletContext().getAttributeNames();
while( e.hasMoreElements() )
{
String n = (String)e.nextElement();
Object v = getServletContext().getAttribute(n);

s.append("<form>")
.append(" nome: <input name=\"nome\" value=\"" + n + "\">")
.append(" valor: <input name=\"valor\" value=\"" + v + "\">")
.append(" Remover? <input name=\"acao\" value=\"remover\" type=\"checkbox\">")
.append(" <input value=\"Alterar\" type=\"submit\">")
.append("</form>");
}

out.print(s);
}
}

Depois de registrado o servlet e o listener no web.xml é só testar. Se por exemplo adicionarmos um atributo de nome pais e valor igual a Brasil, depois alterarmos esse mesmo atributo para Guatemala e ao final removê-lo. Teremos as seguintes linhas escritas no output:

Atributo adicionado: nome=pais, valor=Brasil
Atributo alterado: nome=pais, valorAntigo=Brasil
Atributo removido: nome=pais, valor=Guatemala

Pra que serve e como funciona o ServletContextListener?

A interface ServletContextListener é um listener utilizado para verificar quando uma aplicação é iniciada e finalizada. A classe que implementa essa interface deve sobrescrever os métodos contextInitialized e contextDestroyed que serão chamado assim que a aplicação é iniciada e finalizada respectivamente.

Veja um exemplo de classe implementando este listener:
package meupacote.listeners;

import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;

public class MeuServletContextListener implements ServletContextListener
{
public void contextInitialized(ServletContextEvent e)
{
System.out.println("MeuServletContextListener - iniciado: " +
e.getServletContext().getServerInfo()
);
}

public void contextDestroyed(ServletContextEvent e)
{
System.out.println("MeuServletContextListener - finalizado");
}
}

Assim que registrármos esse listener no web.xml da aplicação, sempre que o contexto for recriado o método contextInitialized será chamado, escrevendo no output "MeuServletContextListener - iniciado: " seguido das informações do container utilizado. Como eu utilizo o tomcat 5, é apresentada a seguinte: "Apache Tomcat/5.5.17". Já o método contextDestroyed será chamado sempre que a aplicação for finalizada.

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.

Extensões do Firefox para desenvolvedores web

Compartilho aqui com vocês os pluggins, agora chamados de addons, que utilizo no meu Firefox 2. São extensions para auxiliar a depuração de sistemas e que não podem faltar a um desenvolvedor web.
  • Firebug - Melhor pluggin para debugar javascript: Exibe exatamente quando e onde um erro ocorre. Rastrea as chamadas ajax e permite analise do html e css da página.
  • GreaseMonkey - Permite definir códigos javascript sempre que determinadas páginas forem abertas. Muito útil para exibir funcionalidades beta em um determinado site somente para os usuários que você escolher, ou para reconfigurar páginas que você costuma visitar.
  • WebDeveloper - Diversas ferramentas para desenvolvedores web. A que mais utilizo é a manutenção de cache e de cookies. Mas também é interessante a de visualizador de campos de formulários.
  • JSView - Cria um atalho para exibir todos os arquivos js e css que uma página carrega, inclusive aqueles lidos dinamicamente. Depois de instalar ele é preciso habilitar a opção de exibir seu icone na barra de status do firefox.
  • Live HTTP Headers - Exibe todas as requisições HTTP que o Firefox faz. Permite filtrar para exibir arquivos de imagem, flash, css entre outros ou não;
  • Aardvark - Permite analisar o código html gerado na página, inclusive o que foi criado apartir de javascript. Basta apertar com botão direito, e no menu selecionar "Start Aardvark", que os elementos html serão destacados. Apertando a tecla h verifica-se todas as opções do addon.
  • IE Tab - Veja paginas no Firefox como se estivesse no Internet Explorer. Ideal para pessoas como eu que preferem testar em outra aba da raposa ao invés de abrir uma janela do IE.
  • Resizeable Form Fields - Faz com que alguns campos de formulários possam ser redimensionados.
  • del.icio.us - Cria dois botõezinhos do Delicious, um para acessar diretamente seus favoritos e outro para adicionar a página que você está visitando.
  • XPather - Adiciona um item no menu do botão direito que indica o XPath para acessar determinado elemento no html.
Alguns desses pluggins possuem macetes para funcionar. Não postei todos eles aqui por falta de tempo. Portanto se você tiver algum problema comente aqui o problema que, se caso eu tenha tido o mesmo, eu respondo com a solução.

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.

A busca de seu site no firefox

ATENÇÃO: O seguinte artigo mostra como adicionar uma busca somente no Firefox. Para ver como adicionar em diversos navegadores, como o próprio Firefox e o Internet Explorer, utilizando o padrão OpenSearch abra o artigo Busca com OpenSearch no Firefox e IE7




Quer disponiblizar a busca de seu site ou blog direto no Firefox? Isso é fácil fácil, basta primeiro criar um arquivo src contendo um xml nos moldes do seguinte exemplo:
<search 
name="Titulo do site"
description="Descricao do site"
action="http://endereco.do.site/busca"
searchform="http://endereco.do.site/busca"
method="GET"
version="1.0">
<input name="q" user="">
</search>
<browser
update="http://endereco.do.site/busca-firefox.src"
updateicon="http://endereco.do.site/busca-firefox.png"
updatecheckdays="7">
</browser>


Calma calma, parece um descritor complicado mas não é. Primeiro na tag search devemos preencher o titulo do site e depois a descrição. O atributo action indica o executor da busca: um servlet, cgi, o que for, que receberá um determinado parâmetro de busca. O nome desse parâmetro é indicado na tag input.

A tag browser indica quando esses descritor deve ser atualizado e onde deve ser buscado. Veja que tem o endereço de um icone, atributo updateicon. É importante que o tamanho desse icone seja 16x16, caso contrário fica esquisitão.

Depois de criado seu e disponibilizado o descritor, basta colocar o link para que os usuários adicionem sua busca no firefox. Segue o exemplo do javascript que faz isso:
<a href="javascript:window.sidebar.addSearchEngine('http://endereco.do.site/busca-firefox.src','http://endereco.do.site/busca-firefox.png','Busca no meu site','png');">
Adiciona busca do meu site
</a>


Recentemente disponibilizamos aqui na globo.com a busca do nosso portal de vídeos, o Globo Vídeos, para ser colocado no firefox. Veja como fica:

Adiciona busca do Globo Vídeos

quinta-feira, 5 de abril de 2007

Windows Media Player embed só com a barra de status

No post ClassID do Windows Media Player embed eu descrevi um problema que estava tendo para exibir um player embed no internet explorer com somente a barra de status. Utilizando o classid 6BF52A52-394A-11d3-B153-00C04F79FAA6 isto se tornava impossivel.

Eis então que tive uma idéia simples, que poderia ser considerada uma técnica POG. A solução encontrada foi redimensionar o player para o tamanho dos controles somado ao tamanho da barra de status, e encapsular isso num div com overflow hidden, do tamanho da barra de status. Veja o código:

<div style="overflow: hidden; width: 300px; height: 19px;">
<object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6"
id="MeuPlayer" name="MeuPlayer"
height="64" width="300"
type="application/x-mplayer2"
>
<param name="uiMode" value="full"/>
<param name="URL" value="nao_se_afobe_nao.wma"/>
</object>
</div>



Isso pode ser considerado uma técnica POG porque não é garantido que em versões futuras do Internet Explorer e do Windows Media Player o tamanho da barra de controles e de status seja 64 pixels, e que o tamanho da barra de status sozinha seja de 19 pixels.

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);
}

terça-feira, 3 de abril de 2007

Política de privacidade

Este site pode utilizar cookies e/ou web beacons quando um usuário
tem acesso às páginas. Os cookies que podem ser utilizados associam-se
(se for o caso) unicamente com o navegador de um determinado
computador.

Os cookies que são utilizados neste site podem ser instalados pelo
mesmo, os quais são originados dos distintos servidores operados por
este, ou a partir dos servidores de terceiros que prestam serviços e
instalam cookies e/ou web beacons (por exemplo, os cookies que são
empregados para prover serviços de publicidade ou certos conteúdos
através dos quais o usuário visualiza a publicidade ou conteúdos em
tempo pré determinados). O usuário poderá pesquisar o disco rígido de
seu computador conforme instruções do próprio navegador.

Usuário tem a possibilidade de configurar seu navegador para ser
avisado, na tela do computador, sobre a recepção dos cookies e para
impedir a sua instalação no disco rígido. As informações pertinentes a
esta configuração estão disponíveis em instruções e manuais do próprio
navegador

* O Google, como fornecedor de terceiros, utiliza cookies para exibir anúncios no seu site.
* Com o cookie DART, o Google pode exibir anúncios para seus usuários com base nas visitas feitas aos seus e a outros sites na Internet.
* Os usuários podem desativar o cookie DART visitando a Política de privacidade da rede de conteúdo e dos anúncios do Google.

ClassID do Windows Media Player embed

Quem está colocando um Windows Media Player embed em uma página precisa ficar atento sobre as configurações que funcionam e as que não funcionam para um determinado classid. Contudo, isso só é necessário para o Internet Explorer. No Firefox, que utiliza a tag embed ao invés da object não há esse problema.

O que descobri é que para o classid 6BF52A52-394A-11d3-B153-00C04F79FAA6, que seria para WMP 7 ou superior, os parâmetros ShowControls e ShowStatusBar não funcionam. Assim, para poder mecher no layout do player deve-se utilizar o parâmetro uiMode, parâmetro que tem sérias limitações que estão me dando uma baita dor de cabeça.

Isso porque o que eu preciso é de um player embed que só possua a barra de status, mas não achei até agora um valor que faça isso para o parâmetro uiMode.

O outro classid do windows media player, 22d6f312-b0f6-11d0-94ab-0080c74c7e95, serve apenas para o WMP com versão inferior a 7. Com este classid é possível utilizar todos os parâmetros que preciso. Mas, como os arquivos que desejo abrir precisam de codecs específicos de versões superioras, não posso utilizar esse classid.

Ou seja, até agora estou ferrado.

Atualização: Solução proposta em Windows Media Player embed só com a barra de status