response.setContentType("multipart/x-mixed-replace");
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:
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:
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:
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).
<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:
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.
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
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:
Js:
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:
Js:
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>
function exibirTag() {
alert( document.popupNode.tagName );
}
Xul:
<popup id="contentAreaContextMenu">
<menuitem id="itemMenuCopiarPagina" label="Copiar pagina" oncommand="copiarPagina()"/>
</popup>
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:
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:
A saída esperada é:
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;
}
}
$eu = new Pessoa("Tiago",25);
echo "<br/>" . $eu->nome . " tem " . $eu->idade . " anos";
echo "<br/>Atributo nao existente: " . $eu->atributoNaoExistente;
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.
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:
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:
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.
É 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);
}
}
/**
* @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);
}
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);
}
}
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.
Assinar:
Postagens (Atom)