segunda-feira, 21 de abril de 2008

Demora do Firefox para começar a receber os eventos de um Comet

Quando abrimos um HTTP Stream, ou Comet como é chamado hoje em dia, no Firefox, demora um tempo até que os dados comecem a ficar disponíveis. Ao que parece ele espera haja 1kb de dados já recebidos para começar a deixá-los disponíveis para uso. Contudo, há uma forma de habilitar o processamento dos eventos do Comet no Firefox diretamente sem esperar esse 1kb inicial. Basta definir o content type do retorno como multipart/x-mixed-replace. Em Java seria algo como o mostrado abaixo:
response.setContentType("multipart/x-mixed-replace");

sábado, 19 de abril de 2008

Ativando o conector NIO no Tomcat 6

Para utilizar o CometProcessor do Tomcat 6 é preciso configurar o servidor para utilizar o NIO Connector ao invés do conector http padrão. Caso contrário, ao acessar o seu CometProcessor você receberá o seguinte erro:
message HTTP method GET is not supported by this URL

description The specified HTTP method is not allowed for the requested resource (HTTP method GET is not supported by this URL).
Para habilitar então este conector basta alterar no arquivo server.xml o atributo protocol do conector, deixando-a mais ou menos da seguinte maneira:
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" 
connectionTimeout="20000"
redirectPort="8443" />

terça-feira, 15 de abril de 2008

Globo.com no Fisl 9.0

Do dia 17 a 19 de Abril estarei em Porto Alegre participando do Fisl 9.0 junto com Guilherme Chapiewski, Tiago Peczenyj e mais um monte de gente da Globo.com. Estaremos lá para conversar um pouco sobre os problemas e soluções de um dos maiores portais da internet brasileira e todo nosso esforço para basearmos essas soluções em software livre. Especificamente estarei lá para conversar sobre o portal Globo Vídeos e as nossas ultimas pesquisas com software livre. Quem quiser me encontrar para bater um bom papo nerd é só me procurar no stand da Globo.com. É claro que não estarei o tempo inteiro lá, pois assistirei diversas palestras, no entanto farei o possível para ficar o máximo de tempo lá. Além disso criei um grupo de fotos no 8P para publicarmos as fotos do evento. Assim, se você quiser participar do grupo de fotos do Fisl 9.0 é só se associar e publicar suas fotos. Por hora é só, vejo vocês lá!

segunda-feira, 14 de abril de 2008

Bash para redimensionar imagens

Toda segunda-feira é a mesma história, depois de um final de semana de festas e diversão, todo mundo fica solicitando, porque não dizer exigindo as fotos tiradas durante os eventos. O problema é que fotos de câmeras digitais costumam ser grandes, tornando dificil a transferencia para os amigos.

O Caio Moritz postou em seu blog uma dica de como redimensionar imagens pela linha de comando usando o comando mogrify. O problema é que o bash que ele criou redimensiona as imagens sem manter as originais. Então, tomei a liberdade de incrementá-lo um pouco, devido às minhas necessitades. Segue abaixo como ficou:
#!/bin/sh
if [ -z $2 ]
then
echo "Uso: resizepics.sh diretorioFonte diretorioDestino";
exit;
fi

echo "Criando diretorio $2";
mkdir "$2";

echo "Copiando arquivos de $1 para $2";
cp "$1/"*.jpg "$2";

echo "Entrando no diretorio $2";
cd "$2"

echo "Redimensionando imagens";
for img in *.jpg;
do
echo "$img";
mogrify -resize 800x600 "$img";
done
Pronto, salve com o nome de resizepics.sh. Para executá-lo é só informar como primeiro parâmetro o diretório onde estão as fotos, e no segundo o diretório onde serão colocadas as fotos redimensionadas. É claro que para isso funcionar você precisa instalar o pacote imagemagick conforme informado no post do Caio.

sexta-feira, 4 de abril de 2008

Brincando de extensões com o chrome do Firefox

Desenvolver extensões para o Firefox é algo muito divertido. Mas há certas questões que nos deixam de cabelo em pé. Basicamente por falta de exemplos e tutoriais simples. No caso, eu procurava duas coisas: Como acessar o elemento html que foi clicado com o botão direito do mouse, e como copiar um determinado trecho selecionado para a área de transferências (clipboard).

Nessas horas então, nada melhor que analisar os códigos contidos no Chrome do Firefox. Descompactando os arquivos browser.jar e toolkit.jar, localizados no diretório ${FIREFOX_HOME}/chrome, podemos verificar diversos bons exemplos.

No arquivo browser.js do pacote browser.jar por exemplo, pude verificar que para acessar o elemento clicado com o botão direito basta utilizar a notação document.popupNode. O exemplo abaixo mostra de maneira simples um Xul e um Js de um item no menu do botão direito cuja única função é exibir a tag html do elemento clicado com o botão direito.

Xul:
<popup id="contentAreaContextMenu">
<menuitem id="itemMenuExibirTag" label="Exibir tag" oncommand="exibirTag()"/>
</popup>
Js:
function exibirTag() {
alert( document.popupNode.tagName );
}
Já para implementar a função de copiar para a área de transferência, verifiquei no arquivo browser.xul do pacote browser.jar que os menus de copiar do próprio navegador chamavam a função goDoCommand com o parâmetro cmd_copy. Encontrei essa função no arquivo globalOverlay.js do pacote toolkit.jar. Havia nele um comentário informando que a função era apenas para manter compatibilidade com versões antigas, e realmente a única coisa que ela fazia era repassar a função para o método doCommand da classe CommandUpdater. Abaixo mostro um exemplo de item que seleciona todos os itens de uma página e copia o conteúdo para o clipboard:

Xul:
<popup id="contentAreaContextMenu">
<menuitem id="itemMenuCopiarPagina" label="Copiar pagina" oncommand="copiarPagina()"/>
</popup>
Js:
function copiarPagina() {
CommandUpdater.doCommand('cmd_selectAll');
CommandUpdater.doCommand('cmd_copy');
}

quinta-feira, 3 de abril de 2008

Definindo atributos somente leitura em uma classe PHP

O modificador private em PHP, assim como em quase todas as linguagens, impede que membros de uma classe sejam acessados para leitura e escrita. Mas e se você deseja que os atributos de uma classe sejam privados para escrita mas não para leitura? Uma solução simples seria criar métodos get para cada atributo que se deseja liberar a leitura. Mas essa solução é muito verbosa, e como costumo dizer, se você deseja fazer algo desse tipo, melhor então usar Java.

O PHP possui o que no site está descrito como métodos mágicos. No caso para liberarmos a leitura de atributos privados de uma classe, utilizaríamos o método mágico __get. Esse método é chamado sempre que um atributo da classe é acessado. Veja abaixo como ficaria a implementação desse método de forma a liberar todos os atributos da classe:
class Pessoa {

private $nome;
private $idade;

function Pessoa($nome,$idade) {
$this->nome = $nome;
$this->idade = $idade;
}

function __get($atributo) {
echo "<br/>Leu atributo $atributo";
return $this->$atributo;
}
}
Repare que interessante a sintaxe do corpo do método __get. Eu retorno um atributo do objeto atual que contenha o nome enviado por parâmetro. Para verificarmos o funcionamento dele podemos testar com o seguinte código:
$eu = new Pessoa("Tiago",25);
echo "<br/>" . $eu->nome . " tem " . $eu->idade . " anos";
echo "<br/>Atributo nao existente: " . $eu->atributoNaoExistente;
A saída esperada é:
Leu atributo nome
Leu atributo idade
Tiago tem 25 anos
Leu atributo atributoNaoExistente
Atributo nao existente:

terça-feira, 1 de abril de 2008

Mock de classe no PHPUnit executa o construtor

O mock de classes no PHPUnit não funciona muito bem, o ideal, claro é mocar interfaces, mas quando isso não é possível é preciso estar ciente de que o construtor da classe mocada será executado e portanto o teste ficará um tanto falho.

É possivel identificar facilmente esse problema com o código abaixo. No caso mocarei a classe ClasseUtilizada para ser utilizada na classe ClasseASerTestada. Ao executar o teste é possível verifique que o echo dentro do construtor será executado erroneamente.
class ClasseUtilizada {   
function ClasseUtilizada() {
echo "\n[passou no construtor de ClasseUtilizada]\n";
}
public function fazAlgumaCoisa() {
return "uhuuu";
}
}
class ClasseASerTestada {
function ClasseASerTestada($in) {
echo "\n[" . $in->fazAlgumaCoisa() . "]\n";
}
}
class MeuTeste extends PHPUnit_Framework_TestCase {
/**
* @Test
*/
public function teste_com_classe() {
$mock = $this->getMock("ClasseUtilizada");
$mock->expects($this->once())
->method('fazAlgumaCoisa')
->will($this->returnValue(2));
new ClasseASerTestada($mock);
}
}
Uma forma de contornar isso é se aproveitar das características dinâmicas do PHP para simplesmente criar um Mock de uma classe que não existe. Mas pra isso é preciso informar no método getMock não só o nome de uma classe inexistente, como também a lista de métodos que a classe teria. Veja como ficaria abaixo:
    /**
* @Test
*/
public function teste_com_classe_inexistente_indicando_metodos() {
$mock = $this->getMock("ClasseUtilizadaMock", Array('fazAlgumaCoisa'));
$mock->expects($this->once())
->method('fazAlgumaCoisa')
->will($this->returnValue(4));
new ClasseASerTestada($mock);
}
Se por um acaso você não indicar o segundo parâmetro, que é um array com os métodos que a classe possui, um erro parecido com este será exibido: "Fatal error: Call to undefined method Mock_ClasseUtilizadaMock_4322e2fd :: fazAlgumaCoisa()".

O problema dessa solução é o caso em que a classe a ser utilizada possui verificação de tipo no recebimento dos parâmetros. Como a classe mock criada dinamicamente não é do tipo esperado, ocorrerá um erro. Veja um exemplo de como isso aconteceria abaixo:
class ClasseUtilizada {   
function ClasseUtilizada() {
echo "\n---->passou no construtor de ClasseUtilizada<-----\n";
}
public function fazAlgumaCoisa() {
return "uhuuu";
}
}
class ClasseASerTestadaComVerificacaoDeTipo {
function ClasseASerTestada(ClasseUtilizada $in) {
echo "\n[" . $in->fazAlgumaCoisa() . "]\n";
}
}
class MeuTeste extends PHPUnit_Framework_TestCase {
/**
* @Test
*/
public function teste_com_classe_inexistente_na_classe_com_verificacao_de_tipo() {
$mock = $this->getMock("ClasseUtilizadaMock", Array('fazAlgumaCoisa'));
$mock->expects($this->once())
->method('fazAlgumaCoisa')
->will($this->returnValue(5));
new ClasseASerTestadaComVerificacaoDeTipo($mock);
}
}
Nesse caso o erro exibido será "Argument 1 passed to ClasseASerTestadaComVerificacaoDeParametro :: ClasseASerTestadaComVerificacaoDeParametro() must be an instance of ClasseUtilizada"

Para esses casos não tem jeito, é preciso alterar as classes para que exista uma interface a ser mocada. Mas eu sugiro que não utilize a verificação de tipo nos parâmetros, caso contrário, seria melhor deixar de lado uma linguagem dinâmica como PHP e usar uma mais estática como Java.