terça-feira, 4 de dezembro de 2007

Gmail + Talk + ICQ + AIM + ?

Post rápido para novidade excelente: o google (eles vão dominar o
mundo) acaba de integrar o AIM ao gmail. Eu, velho usuario do ICQ,
entrei na onda, já que ICQ e AIM é quase que a mesma coisa.
Não deixem de conferir a novidade em:

http://gmailblog.blogspot.com/2007/12/gmail-chat-aim-crazy-delicious.html
http://www.undergoogle.com/blog/2007/12/google-talk-se-integra-ao-aim.html

e no seu email, claro!!! :D

quinta-feira, 29 de novembro de 2007

Ando devagar porque já tive pressa...

Ando devagar porque já tive pressa
e levo esse sorriso, porque já chorei demais
Hoje me sinto mais forte, mais feliz quem sabe
eu só levo a certeza de que muito pouco eu sei, eu nada sei...
Parafraseando Almir Sater, o NetBeans 6 parece se encaixar perfeitamente.

Em muitos casos estou achando mais lento que a versão 5.5, e não é um pouco mais lento... editar arquivos XML que sejam um pouco extensos -- estamos falando de 600 linhas -- é impossível.

Eu, sinceramente, esperava mais. Não estou desmerecendo o empenho da equipe, acho que as novas funcionalidades ficaram fantásticas, até me adaptei ao novo formato de cores!
Mas, como na 5.5, eu sou mais rápido para completar um /h:outputText do que 2.16GHz! :-) Estou me referindo ao editor em situações para editar JSP/JSF e XML. Em Java ficou (como já era) rápido, mas agora mais organizado. Contudo, experimente ir no início do seu JSP e substituir html por htm:html ou mesmo aguardar as opções de h:datatable.
Sem querer me gabar, mas preferiria não precisar digitar... e pelo jeito vou continuar.

Parece que nem todos estão preocupados com desempenho. No anúncio dos resultados da pesquisa de aceitação do RC2 do NetBeans, no blog do Roumen, 93% dos usuários acham que está pronto para a versão final. Inclusive há um comentário dizendo que o desempenho é importante, mas inserir mais funcionalidades é principal?!?! Desempenho que venha no 6.1...

Bom, para editar meu XML vou ter que apelar para a concorrência. Mas vou continuar relatando meus problemas para a equipe...
Cada um de nós compõe a sua história,
e cada ser em si, carrega o dom de ser capaz, e ser feliz.

sexta-feira, 23 de novembro de 2007

NetBeans 6.0 não permite acentuar commits no Subversion

No NetBeans 6, mesmo o RC2, ainda não é possível acentuar commits.
Ao tentar comitar a mensagem Test: á é í ó ú ç ã (a e i o u c a), retorna o seguinte erro:

svn: Commit failed (details follow):
svn: Can't convert string from native encoding to 'UTF-8':
svn: Test: ?\135 ?\142 ?\146 ?\151 ?\156 ?\141 ?\139 (a e i o u c a)


Achei já o bug relatado e convido a todos para votarem :)

Ah, a dica anterior não funciona no NB6.

Não é mais possível navegar com MS Explorer!

Não, não é o internet explorer...

... mas também, quem será que foi o estagiário que botou o nome neste navio?

Tomara que não tenha sido um Access violation!



Pode até ser humor negro, mas não pude deixar de postar...




Notícia do terra.

quarta-feira, 14 de novembro de 2007

NetBeans 6.0 rc1 oficialmente lançado

O NetBeans 6.0 release candidate 1 foi oficialmente lançado. A versão 6.0, que já venho usando há mais de 2 semanas, têm apresentado ainda alguns problemas (os quais já submitamos aqui e aqui), mas está bastante interessante.
O editor realmente ficou mais agradável e está mais "inteligente"... Já estou baixando a nova versão para ver se houveram melhorias significativas.

A dúvida é: conseguirão resolver todos os problemas até o lançamento? Só de bugs, há uma lista de mais de 1.600 ítens em aberto, programados para o 6.0...

Chamadas dinâmicas de funções em JavaScript

Em alguns casos precisamos que um evento execute uma função, como definir o onclick, por exemplo. Nestes casos, você não pode fazer:
elemento.onclick = funcao();
Pois ele tentará executar a chamada de funcao() nao hora.
Colocar entre aspas simplesmente não efetuará chamada alguma. O correto é:
elemento.onclick = funcao;
function funcao() {
...
};
Funciona perfeitamente, e atendeu às minhas necessidades. Contudo, desta forma não permite passar parâmetros.
A idéia então passa a ser criar uma nova função a ser executada nesta chamada que repasse os parâmetros. Como criar uma segunda função e utilizar conforme acima fica "feio", dá para criar diretamente uma função na variável do evento onclick.
Não testei a parte abaixo, mas a lógica acho que é adequada:
elemento.onclick = function() { funcao('param1'); }
function funcao(parametro) { ... }
:)

segunda-feira, 12 de novembro de 2007

Explanação visual de consultas SQL (Joins)

Buenas,
Hoje somente repassando um link do Coding Horror sobre joins. Muito
legal, apesar de ser basico. O visual ajuda a simplificar. Vale a
lida. Abraços.

http://www.codinghorror.com/blog/archives/000976.html

Mais sobre joins em:
http://www.postgresql.org/docs/8.2/static/tutorial-join.html
http://en.wikipedia.org/wiki/Join_(SQL)

terça-feira, 6 de novembro de 2007

Acertando o relogio do Tomcat

Buenas pessoal,

Apos um pequeno quebra-cabeças para acertar os ponteiros do meu tomcat, acabo de fazê-lo funcionar. De forma bem fácil, visto as alternativas...

Escrevi esse pequeno passo-a-passo, caso alguem tenha a mesma duvida, pra nao perder tempo.

Mas antes, quero registrar minha crítica ao horario de verão no Brasil. Li uma frase (nao me recordo o autor) que dizia: "Em todos os lugares do mundo, o horario de verão segue uma fórmula. No Brasil, segue uma lei". Esta frase explica o quão f****** sao os pobres analistas brasileiros. Choramingos a parte, vamos ao tuto:


Primeiramente, editando o catalina.sh, eh preciso declarar o JAVA_HOME (atenção para os caminhos!!!):
JAVA_HOME="/usr/lib/jvm/java-1.5.0-sun/"

Depois, deve-se adicionar a palavra timefix antes da chamada do bootstrap, em todos os casos, como a seguir:
timefix org.apache.catalina.startup.Bootstrap

A seguinte biblioteca deve ser posta no /common/lib:
http://code.google.com/p/timefix/downloads/list

Por último, no arquivo setclasspath.sh, na linha que zera o CLASSPATH, deixe-a assim:
CLASSPATH="$CATALINA_HOME"/common/lib/timefix-1.0.jar

E voilà! Se tudo ocorreu bem (difícil), seu tomcat irá iniciar sabendo que horas são! Mas se não der certo, mande um email pra lula@brasil.gov.br e pergunta porque diabos ele bota o horário de verão quando ele quer. As vezes ele demora pra responder, pois, dizem as más línguas, o "aerolula" nao tem internet.

[]'s

sexta-feira, 26 de outubro de 2007

Horario de verao no java / tomcat

Bom, se você chegou aqui porque está realmente com problemas de
horario de verao no tomcat, você tá na m****. Passei por esse problema
hoje e achei um post que supostamente resolve o problema. Levarei até
o final do horario de verao pra conseguir fazer funcionar o esquema,
mas estou postando mesmo assim, hehehe.

http://www.javafree.org/javabb/viewtopic.jbb?t=12070

[]'s

Compilando pacotes no Debian/Ubuntu com apt-build

Buenas pessoal,
Para os chatos de plantao, como eu, a performance do sistema é
essencial. Mas temos que convir que baixar codigo fonte, resolver
dependencias, somente para ganhar alguns milissegundos na
inicializacao, e alguns Kb de memoria, nao tem lá um custo-beneficio
razoavel. Eis que, navegando pela net despretenciosamente, achei um
post no "Viva o Linux" do Fabio Maran sobre a ferramenta apt-build.
Estou usando-a desde entao e tenho gostado muito! É bastante facil de
usar.

Inicie instalando o dito:
sudo apt-get install apt-build

Depois, use-o sem dó:
sudo apt-build install <pacote>

E voilà!

Dica original: http://www.vivaolinux.com.br/dicas/verDica.php?codigo=9429

quarta-feira, 24 de outubro de 2007

Horário de verão no Mac!

Para quem está alterando manualmente o horário de verão no Mac, há
uma solução blog Right-it que trata justamente disto!

Gracias, Google!

sexta-feira, 19 de outubro de 2007

Codigo Java do BOPE

Depois de bastante tempo sem nada interessante para postar (lançamento
do Ubuntu e coisinhas pequenas assim nao me chamaram muito a atençao
ultimamente... só a oktoberfest, mas...) recebi por email o codigo
JAVA do treinamento do pessoal do BOPE, que segue abaixo:

/**
* O Bope foi criado para atuar quando a policia perde o controle
* E no rio de janeiro isso acontece com bastante frequencia
*/

class Bope{

private String nome;
private int qtdeVitimas = 1; // ja começa bem!
public Bope(String nome){
this.nome = nome;

}

// sobrecarga do método ondeTaOBaiano
public void ondeTaOBaiano(Estudante e){
e.sabeVoarEstudante();
}

public void ondeTaOBaiano(Traficante t){
t.levaSacoNaCabeca();
}

// exemplo de método final!

public final Doze encontreiOBaiano(Baiano b){
return b.naCaraNaoQueEhPraNaoEstragarVelorio();
}

}

public class Treinamento{
public static void main(String [] xxx){
// Apresento o capitão nascimento

Bope instrutor = new Bope("01?); //Capitao Nascimento
try{

// de cada 100 policiais que fazem o curso do Bope,
// so se formam 5, e eu, quando me formei parceiro,
// eramos apenas 3.

Turma.tentaFazerCursoBopeCom(capitao);

while(aluno.count >= 3){
aluno.pedePraSair();

if(aluno istanceof Cafetao){
capitao.say("Pede pra sair!");
capitao.say("Seu Lugar Eh Com Puta!");
}
if(aluno istanceof PorraLoka){
capitao.say("Tira essa farda preta!");
capitao.say("Voce nao eh cavera. voce eh MULEQUE!");
}
if( aluno.isXerife() ) aluno.desiste();
}

} catch (PolicialCorruptoEncontrado pce){
} catch (PolicialFracoEncontrado pfe){
} catch (PolicialSemABandoleiraNessaAlturadoCampeonato e) {
}

}

}


Não recebi o autor do dito, então nao há créditos essa vez!
:)

quarta-feira, 3 de outubro de 2007

PG Conference Brasil 2007

Como um bom evangelista desenvolvedor Postgres, fiquei empolgado em ver que estão confirmadas presenças internacionais na conferência nacional (Josh Berkus e Bruce Momjian).

Parabéns à equipe de organização, farei o possível para participar.

Os que tiverem interesse, há mais detalhes em http://www.temporealeventos.com.br/?area=80

domingo, 9 de setembro de 2007

Anti-vírus (open source) para Windows

Resolvi melhorar o desempenho de uma máquina Windows e, claro, a primeira coisa que mais consome memória e deve ser revista, é o anti-vírus.
Um colega de trabalho (valeu Fern) comentou estes dias sobre o ClamWin, um anti-vírus open source que é baseado no famoso ClamAV, utilizado largamente em servidores.
Minha aposta é que seja mais leve (é meio difícil confirmar agora, já que mexi em outras coisas também), mas o fato de ser com código livre, licença GNU GPL, já vale a pena.

Para baixar, acesse http://www.clamwin.com/!

quarta-feira, 29 de agosto de 2007

Virtualizacao de Desktops no Mac

Para quem tem problema de falta de espaço em tela, e/ou nao gosta de
ficar minimizando e maximizando.
Uma boa opcao para Mac OS X 10.4 é o VirtueDesktop no endereco http://
virtuedesktops.info/
Apesar do criador parar o desenvolvimento, esta numa versao bem estavel.
Ah! Funciona em PowerPC e Intel-based.
Fui...

sexta-feira, 24 de agosto de 2007

Trocando Icones no Mac

Após pegar o jeito, fica bem fácil e o interessante é que dessa forma
podemos pegar o icone facilmente de qualquer aplicativo.

Para Copiar:
1 - Selecione o arquivo que contem a imagem (icone) desejada (clicar
uma unica vez)
2 - Tecle Apple + i (Teclas de Atalho para Obter Informacoes)
3 - Selecione (Clicando uma unica vez o desenho do Icone que aparece
no canto superior esquerdo)
4 - Tecle Apple + c (Teclas de atalho para copiar)

Para Colar:
1 - Selecione o arquivo que deseja trocar de icone (clicar uma unica
vez)
2 - Tecle Apple + i (Teclas de Atalho para Obter Informacoes)
3 - Selecione (Clicando uma unica vez o desenho do Icone que aparece
no canto superior esquerdo)
4 - Tecle Apple + v (Teclas de atalho para colar)

É isso, até a próxima.

CepNet/PostNet no iReport/Jasper

Na plataforma de desenvolvimento:

1 - Criar um Jar com o codigo abaixo...

package meuPostNet;
import java.awt.Color;
import java.awt.Image;
import com.lowagie.text.pdf.BarcodePostnet;
public class Postnet {
public static Image getImage(String _codigo) {
Image image = null;
try {
BarcodePostnet iTextPostnet = new BarcodePostnet();
iTextPostnet.setCode(_codigo);
image = iTextPostnet.createAwtImage(Color.BLACK, Color.WHITE);
image = new javax.swing.ImageIcon(image).getImage();
} catch (Exception ex) {
ex.printStackTrace();
}
return image;
}
}
2 - Incluir esse Jar na biblioteca (lib) da aplicacao.


No iReport:
1 - Incluir uma imagem com os atributos:
Expressao da imagem = meuPostNet.Postnet.getImage('99999999')
onde '99999999' pode ser a variavel com o cep de 8 digitos desejado.

Classe da expressao = java.awt.Image

E é só... Até a proxima!

quinta-feira, 23 de agosto de 2007

Recuperação de Arquivos Free

Post rápido, sem mais delongas. Um amigo estava com problemas
(formatou o HD) e achamos este programa, free, para recuperação dos
dados:
http://www.officerecovery.com/freeundelete/

Apesar de ja ter usado o Easy Recovery Pro, ele é pago (e muito bem
pago). Este programa é pequeno e mostra a que veio.

terça-feira, 21 de agosto de 2007

Criando assinaturas HTML no Apple Mail

O Apple Mail, por padrão, não permite criar assinaturas formatadas.
Mas há como contornar...

1. Crie uma assinatura no Mail (texto mesmo);
2. Saia do Mail;
3. Crie a página web com qualquer editor;
4. Abra a mesma com o Safari;
5. Salve-a no formato webarchive;
6. Coloque este webarchive em ~Library/Mail/Signatures, com o nome da
assinatura que você quer substituir.

Importante: ~ significa seu diretório home (normalmente /users/
SEUUSUARIO

Importante 2: Você precisa saber qual é a assinatura que você quer
sobrescrever (há um arquivo .webarchive já), porém se você tiver mais
de uma assinatura isto não é trivial. Para descobrir, veja no arquivo
SignaturesByAccount.plist existente no diretório de assinaturas.

terça-feira, 7 de agosto de 2007

Abrindo arquivos do Microsoft Oficce 2007 no OpenOffice e Linux

Bom, me deparei com um problema hoja, que era abrir um arquivo do
office 2007 (docx) no meu openoffice. Achei a dica e compartilho:
http://www.sigmundvoid.com/?p=81

[]'s

Comparação de arquivos (diff) no OS X

Para quem precisa comparar arquivos e prefere uma interface mais
amigável que o velho e bom diff (ou o abominável subversion, quando
conflita o merge), a Apple disponibiliza o FileMerge (http://
en.wikipedia.org/wiki/Apple_Developer_Tools#FileMerge
).
Faz parte do Developer Tools, e vale a pena dar uma testada...

quarta-feira, 25 de julho de 2007

Removendo aplicativos do OS X por completo!

Embora seja muito simples adicionar/remover aplicativos no OS X (basta arrastá-los para a pasta aplicativos ou para a lixeira!), alguns arquivos podem ficar perdidos em pastas do usuário ou similares. Normalmente são arquivos de preferências ou configurações, mas ficam perdidos!
Porém, nem tudo está perdido!

Neste post exemplifica como instalar o AppTrap, que faz este milagre!

Ahhhhhh, e o software é free :), mas não é open source :(

terça-feira, 24 de julho de 2007

Continuations

Buenas,
Passando rapidinho pelo developerWorks, acabei me deparando com um
software que eu admiro bastante: o Jetty. Apesar de sempre ter usado o
Tomcat para produção, esse servlet container sempre chamou minha
atenção, principalemente pela simplicidade, rapidez e robustez. Agora,
Philip McCarthy trouxe novos detalhes sobre o Comet, novo paradigma
que vem surgindo e que, brevemente, fara parte do nosso cotidiano.
Esperem até o Google começar a usar, hehehe...
O DWR também é um framework/facilitador para programação em ajax que
eu uso cotidianamente e gosto muito. Ainda nao trabalhei com "reverse
ajax", mas acho que será o novo hype da net.

O excelente artigo pode ser lido em:
http://www.ibm.com/developerworks/java/library/j-jettydwr/index.html?ca=drs-

Recomendo!

sexta-feira, 6 de julho de 2007

quinta-feira, 28 de junho de 2007

Itens duplicados e quadrado preto ao redor do finder?

Depois de instalar um programa no mac, meu micro ficou um tanto quanto estranho.

Botões de reiniciar e desligar ficaram duplicados e no finder sempre ficava um quadrado preto ao redor do que estava selecionado. Sei que isto tem relação com a instalação de programas, mas não de um específico. Depois de algumas pesquisas, encontrei a solução para tal.

Abra o terminal e digite: "sudo chmod 757 ~/" digita a senha e ok. (isto forçará uma permissão incorreta).

Depois, no utilitário de disco, repare as permissões do disco.

pronto, problema resolvido!

quarta-feira, 27 de junho de 2007

Google sugerindo sites?

Pois é... quem sabe até tenha demorado um pouco para sair isto, mas há um novo "serviço", que na verdade é mais um adendo ao iGoogle, onde, com base numa análise de suas buscas anteriores, são sugeridos links para notícias, buscas, páginas, grupos, gadgets e vídeos.
O interessante é que, além disto, ele diz porquê fez aquela sugestão.

Bom, para ativar isto basta incluir uma nova guia e o nome dela deve ser "Recommendations". Deixe a opção estou com sorte marcada... e pronto! O conteúdo será adicionado e atualizado diariamente.

Fonte: http://googleblog.blogspot.com/2007/04/searching-without-query.html

terça-feira, 26 de junho de 2007

Icones em tela no gnome

Para remover (ou selecionar) os ícones que aparecem na tela do gnome,
proceda da seguinte maneira:
-No terminal, digite:
gconf-editor

Na janela que abra, no menu a esquerda, selecione
"apps>nautilus>desktop". A direita aparecerá a lista de itens a serem
exibidos.

Dica do pessoal da Tux Masters, acessível em:
http://tuxmasters.blogspot.com/2007/06/retirando-os-cones-do-sistema-no-gnome.html
O blog tem umas dicas bem legais. Recomendo uma navegação por ele ;)

sexta-feira, 22 de junho de 2007

Enfim um MP3 player para Mac!

Após muita busca e dores de cabeça... um MP3 player para Mac! Cog -- http://cogx.org/ -- é simples e rápido. O que ele faz? Toca música. E só!

Não fica tentando copiar para seu HD, tampouco buscar informações sobre a música ou me oferecer o álbum para a compra. Eu só quero escutar a música.

iTunes, seus dias estão contados...

Valeu Mário pela dica.

segunda-feira, 4 de junho de 2007

Partições no Ubuntu Feisty

Bom, creio que todo mundo ja viu que o ubuntu usa um raio de UUID para
identificar os discos. Entao, agora a pouco tive que reformatar uma
particao com outro sistema de arquivos, e eis que ela nao monta mais
como deveria (como antigamente, diga-se de passagem). Eis que o google
me deu a solução: o comando ls -l /dev/disk/by-uuid/ exibe os
discos/particoes com seu devido(maldito) UUID. Entao é soh alterar no
fstab e rodar um "sudo mount -a" e pronto, sistema "nos conforme"
novamente!

terça-feira, 29 de maio de 2007

Incrementando a performance do seu Debian/Ubuntu

Buenas tchê, depois de algum tempo brigando com a quantidade de
memoria que o novo Ubuntu Feisty devora (e já ter mudado pro Debian
Etch em definitivo em casa), posto aqui algumas dicas que ajudam quem
usa o seu SO ao extremo.

A primeira dica é para o boot concorrente e se aplica a quem tem
processadores multi-cores.
Editando o arquivo /etc/init.d/rc, procure pela string CONCURRENCY que
deve estar assim: CONCURRENCY=none. Altere ela pra CONCURRENCY=shell.
Pronto, mais fácil que tirar doce da boca de piá pançudo.

A segunda, esta sim violenta, principalmente pra quem passa o dia com
o Tomcat recebendo hot-deploys (pra quem nao sabe, o infame nao libera
a memoria que usa). O sistema, apos algum tempo de uso, insiste em
jogar coisas pro swap, mesmo ainda tendo alguns MB de memoria livres.
Pra acabar com a palhaçada, edite o arquivo /etc/sysctl.conf e
adicione a seguinte linha ao final:
vm.swappiness=0

Isso fará com que o sistema nao jogue dados pra swap, e evite ao
máximo usa-la. Mas, como nem tudo sao flores, se vc nao tem muita
memoria (tem apenas uma vaga lembrança) nao seja tão agressivo com o
sistema: Ele aceita valores entre 0 e 100. Dê alguma alegria pra ele!
;)


As dicas postadas aqui foram retiradas do artigo "Tweak ubuntu for
speed", que contem, alem dessas dicas, dicas que sao um pouco mais
arriscadas, que afetam o sistema de arquivos do seu sistema. Se vc for
corajoso (eu fiz, me ferrei e voltei) pode mandar bala.
Veja o artigo completo em:
http://tvease.net/wiki/index.php?title=Tweak_ubuntu_for_speed

terça-feira, 15 de maio de 2007

Montando unidades de rede Windows (samba) no Mac OS X

Por vários dias tive problemas para acessar a rede, pois o PC o qual eu queria conectar não aparecia em rede (nem o grupo do mesmo, sendo que ele era o único). Alterar o grupo não era a melhor opção, pois outras máquinas acessavam o mesmo perfeitamente!

Por burrice minha, não vi o menu do Finder: Ir e então Conectar ao servidor... igual ao do Ubuntu! As vezes me mato de vergonha...

Bom, a página http://lifehacker.com/software/mac-os-x/how-to-mount-a-windows-shared-folder-on-your-mac-247148.php, além de me resolver isto, ainda deu a dica para auto montar ao iniciar, a qual foi muito bem vinda!

É, as vezes tendemos a complicar o que está simples...

(P.S.: algum dia já falei que odeio alguns programas da Apple? O iTunes é o pior player que já vi, desde a época de windows até agora no Mac, e o Safari, enquanto fazia este post, simplesmente travou!)

segunda-feira, 14 de maio de 2007

Beryl + Netbeans

Ultimamente tenho perdido a paciencia com o beryl, pois, toda a vez
que eu abria o netbeans, uma tela cinza aparecia, me obrigando a
iniciar o gerenciador de janelas Metacity e depois o beryl novamente.
Como quase tudo na vida de um usuario linux sao flores (ficou meio
gay, mas tudo bem), há uma solução, e é simples como tirar uma chuleta
da boca de um pittbul com um dente cariado.
Simplesmente adicione a linha abaixo no final do arquivo /etc/environment:
AWT_TOOLKIT="MToolkit"


E voilà!

quarta-feira, 9 de maio de 2007

Reinstalação completa no Debian (Ubuntu)

Esta dica serve, principalmente, para quando precisarmos atualizar o sistema.
Fazendo uma atualização limpa, perde-se os softwares instalados (as
configurações presume-se que o usuario tenha numa partição
(/home/usuario) a parte. Mas há uma maneira de guardarmos a lista de
sofwares que temos instalados para posterior reinstalação
automatizada, seguindo os dois simples passos abaixo.

No seu sistema condenado, rode o seguinde comando:
dpkg --get-selections | grep -v deinstall > ProgramasInstalados.bkp

Apos a reinstalação do sistema, restaure seus programas com o comando:
dpkg --set-selections < ProgramasInstalados.bkp

E pronto! Sistema novo!

terça-feira, 8 de maio de 2007

Reformatar código não funcionando

Hoje estava trabalhando em um fonte e necessitei reformatá-lo, quando me deparei que esta função não estava fazendo nada, mesmo quando ia pelo menu (achei inicialmente que existia algum conflito com meus atalhos).

A dica veio do Diego, onde o plugin "JavaScript Editor", versão 0.2, causa esta incompatibilidade.

Apenas desabilitá-lo e o problema foi resolvido. Interessante foi não localizar problemas similares com outros usuários... fica aqui o registro.

Já tive este plugin funcionando outras vezes, provavelmente deve ser alguma compatibilidade com o idioma português... irei testar em outro momento.

Alteração: precisei mexer em um JS e então habilitei o plugin. Agora ambos funcionam... vai entender...

sexta-feira, 4 de maio de 2007

tirando beep do terminal linux (tty)

Para silenciar o seu terminal (ele faz um barulhinho chato quando usamos tab) edite o arquivo /etc/inputrc e adicione a seguinte linha:
set bell-style none
É possivel que ela esteja comentada, necessitando somente descomentá-la.
Reinicie o terminal e voilá!

quinta-feira, 3 de maio de 2007

Implementando um sistema de login com JAAS no Tomcat

O que é?
O JAAS (Java Authentication and Authorization Service) é uma API para login e controle de acesso de usuários.

Proposta
Implementar um sistema de autenticação personalizado, pois os oferecidos não se adequavam a proposta inicial do sistema.

Problemas Encontrados
Como fazer a comunicação entre o sistema, que está rodando na web com o módulo de login, que está rodando por baixo do Tomcat.

Implementação
O módulo de login foi organizando com a seguinte estrutura:
  • imagemfilmes.auth -> Pacote que contém meu módulo de login
  • imagemfilmes.auth.obj -> Pacote que contém meus objetos auxiliares
  • imagemfilmes.auth.principals -> Pacote que contém as classes extendidas de Principals
IFLoginModule.java
/**
* Modulo de login da ImagemFilmes.
* @author Diego Fincatto
* @since 1.0
*/
public class IFLoginModule implements LoginModule {

private boolean commitSucedido = false;
private boolean operacaoSucedida = false;

private User usuario;
private Connection connection;
private Banco banco;

protected Subject subject;
protected CallbackHandler callbackHandler;
protected Map sharedState;


/**
* Metodo que faz a leitura dos parametros passados.
* @param subject Subject.
* @param callbackHandler CallbackHandler.
* @param sharedState SharedState.
* @param options Mapa com as opcoes definidas no login.conf.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;

//cria um novo banco
Banco banco = new Banco();
banco.setSqlUser((String) options.get("sqlUser"));
banco.setSqlRoles((String) options.get("sqlRoles"));
banco.setBdDriver((String) options.get("bdDriver"));
banco.setBdUser((String) options.get("bdUser"));
banco.setBdPass((String) options.get("bdPass"));
banco.setBdURL((String) options.get("bdURL"));
this.setBanco(banco);
}

/**
* Metodo que efetua o login do usuario.
* @throws javax.security.auth.login.LoginException Caso nao pode efetuar o
* login.
* @return true.
*/
public boolean login() throws LoginException {
Connection conn = null;
try {
conn = this.getConnection();

// recupera o login e senha informados no form
Usuario usrCallBack = this.buscaUsuarioCallback(this.callbackHandler);

// valida o usuario
this.usuario = this.validaUsuario(conn, banco, usrCallBack);
} catch (ClassNotFoundException cnfe) {
this.operacaoSucedida = false;
throw new LoginException("Erro ao conectar com o banco: " + cnfe.getMessage());
} catch (SQLException e) {
this.operacaoSucedida = false;
throw new LoginException("Erro ao obter conexao: " + e.getClass().getName() + ": " + e.getMessage());
} finally {
try {conn.close();} catch (SQLException e) {}
}

// acidiona o usuario e roles no mapa de compartilhamento
this.sharedState.put("javax.security.auth.principal", this.usuario);
this.sharedState.put("javax.security.auth.roles", this.usuario.getRoles());

//remove mensagem de erro
this.setMensagem(this.usuario.getName(), "");

//retorna ok
return true;
}

/**
* Metodo executado depois das funcoes de login e logout.
* @throws javax.security.auth.login.LoginException Caso erro.
* @return true.
*/
public boolean commit() throws LoginException {
// adiciona o usuario no principals
if (this.usuario != null && !subject.getPrincipals().contains(this.usuario)) {
subject.getPrincipals().add(this.usuario);
}

// adiciona as roles no principals
if ( (this.usuario!=null) && (this.usuario.getRoles() != null) ){
for(Role role : this.usuario.getRoles()){
if (!subject.getPrincipals().contains(role)) {
subject.getPrincipals().add(role);
}
}
}

//seta o commit como feito
this.commitSucedido = true;

//retorna ok
return true;
}

/**
* Aborta alguma operacao.
* @throws javax.security.auth.login.LoginException Caso erro.
* @return true.
*/
public boolean abort() throws LoginException {
if (!this.operacaoSucedida) {
return false;
} else if (this.operacaoSucedida && !this.commitSucedido) {
this.operacaoSucedida = false;
} else {
this.operacaoSucedida = false;
this.logout();
}

//limpa os dados da autenticacao
this.subject = null;
this.callbackHandler = null;
this.sharedState = null;
this.usuario.setRoles(new HashSet());

//retorna o estado da operacao
return this.operacaoSucedida;
}

/**
* Metodo que executa logout no sistema.
* @throws javax.security.auth.login.LoginException Caso erro.
* @return true.
*/
public boolean logout() throws LoginException {
// remove o usuario e as roles do principals
subject.getPrincipals().clear();

//retorna ok
return true;
}



/**
* Este eh o metodo responsavel por validar o usuario no logon.
* Se conseguir validar, ja busca as Roles associadas a ele.
* @param conn Conexao com banco.
* @param _usuario Usuario a ser validado.
* @throws javax.security.auth.login.LoginException Caso nao consiga validar
* o usuário.
* @return true.
*/
private User validaUsuario(Connection conn, Banco _banco, Usuario _usuario) throws LoginException {
User retValue = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement(_banco.getSqlUser());
pstmt.setString(1, _usuario.getLogin());

//executa a query
rs = pstmt.executeQuery();

//verifica se o usuario existe na tabela
if (rs.next()) {
String senhaBanco = rs.getString(1);

//verifica se as senhas batem
if (senhaBanco.equals(this.geraMD5(_usuario.getSenha()))){
retValue = new User(_usuario.getLogin());
retValue.setRoles(this.recuperaRoles(conn, _banco, _usuario));
} else {
this.setMensagem(_usuario.getLogin(), "Senha Invalida!");
throw new LoginException("Senha Invalida!");
}
} else {
this.operacaoSucedida = false;
this.setMensagem(_usuario.getLogin(), "Usuario nao localizado!");
throw new LoginException("Usuario nao localizado!");
}

//atualiza o numero de logins efetuados
StringBuilder sql = new StringBuilder();
sql.append("UPDATE usuario_site ");
sql.append("SET acessonum = acessonum+1 ");
sql.append("WHERE email = ? ");

pstmt = conn.prepareStatement(sql.toString());
pstmt.setString(1, _usuario.getLogin());
pstmt.executeUpdate();

//retorna o usuario
return retValue;
} catch (SQLException e) {
this.operacaoSucedida = false;
throw new LoginException("Erro de SQL");
} finally {
try {rs.close();} catch (Exception e) {}
try {pstmt.close();} catch (Exception e) {}
}
}

/**
* Metodo que recupera as roles do usuario.
*
* @return true.
* @param _banco Banco a ser utilizado.
* @param conn Conexao com o banco.
* @param _usuario Usuario a ser pesquisado.
* @throws javax.security.auth.login.LoginException Caso erro.
*/
public Set recuperaRoles(Connection conn, Banco _banco, Usuario _usuario) throws LoginException {
Set retValue = new HashSet();
PreparedStatement statement = null;
ResultSet rs = null;
try {
statement = conn.prepareStatement(_banco.getSqlRoles());
statement.setString(1, _usuario.getLogin());
rs = statement.executeQuery();

//percorre os resultados
while (rs.next()) {
retValue.add(new Role(rs.getString(1)));
}

//adiciona roles estaticas
} catch (SQLException e) {
this.operacaoSucedida = false;
this.setMensagem(_usuario.getLogin(), "Erro ao recuperar roles!");
throw new LoginException("Erro ao recuperar roles!");
} finally {
try {rs.close();} catch (Exception e) {}
try {statement.close();} catch (Exception e) {}
}

//retorna
return retValue;
}

/**
* Este eh o metodo que pega o login e senha informados, independente do
* metodo usado para a autenticacao.
*
* @param _callback Callback de onde virao as informacoes.
* @throws javax.security.auth.login.LoginException Caso erro.
* @return Usuario.
*/
protected Usuario buscaUsuarioCallback(CallbackHandler _callback) throws LoginException {
Usuario retValue = null;
if (_callback == null){
throw new LoginException("Nao foi encontrado um CallbackHandler!");
}

//cria um array de calback para pegar nome de usuario e senha
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("Login");
callbacks[1] = new PasswordCallback("Senha", false);

try {
//pega o callback
_callback.handle(callbacks);
//cria um usuario
retValue = new Usuario();
retValue.setLogin(((NameCallback) callbacks[0]).getName());
retValue.setSenha(new String(((PasswordCallback) callbacks[1]).getPassword()));

//limpa a senha
((PasswordCallback) callbacks[1]).clearPassword();
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException uce) {
throw new LoginException(uce.getCallback().toString() + " nao disponivel!");
}

//retorna o usuario
return retValue;
}
/**
* Funcao que gera MD5
* @param _str String que queremos gerar a md5
* @return retorna o md5 do parametro passado
*/
public static String geraMD5(String _str){
String retValue = "";
try{
//cria uma instancia de Messagedigest
MessageDigest md5 = MessageDigest.getInstance("MD5");
//gera md5
md5.update(_str.getBytes());
byte[] hash = md5.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < retvalue =" hexString.toString();" connection ="="" connection =" DriverManager.getConnection(this.getBanco().getBdURL()," banco =" banco;">

Banco.java
**
* Classe que carrega as informacoes do banco de dados.
* @author Diego Fincatto
* @since 1.0
*/
public class Banco {

private String sqlUser;
private String sqlRoles;
private String bdDriver;
private String bdUser;
private String bdPass ;
private String bdURL;

/** Creates a new instance of Banco */
public Banco() {
this.setSqlUser("");
this.setSqlRoles("");
this.setBdDriver("");
this.setBdUser("");
this.setBdPass("");
this.setBdURL("");
}

public String getSqlUser() {
return sqlUser;
}

public void setSqlUser(String sqlUser) {
this.sqlUser = sqlUser;
}

public String getSqlRoles() {
return sqlRoles;
}

public void setSqlRoles(String sqlRoles) {
this.sqlRoles = sqlRoles;
}

public String getBdDriver() {
return bdDriver;
}

public void setBdDriver(String bdDriver) {
this.bdDriver = bdDriver;
}

public String getBdUser() {
return bdUser;
}

public void setBdUser(String bdUser) {
this.bdUser = bdUser;
}

public String getBdPass() {
return bdPass;
}

public void setBdPass(String bdPass) {
this.bdPass = bdPass;
}

public String getBdURL() {
return bdURL;
}

public void setBdURL(String bdURL) {
this.bdURL = bdURL;
}

}
Usuario.java
/**
* Classe que representa um usuario.
* @author Diego Fincatto
* @since 1.0
*/
public class Usuario {
private String login;
private String senha;

/** Creates a new instance of Usuario */
public Usuario() {
this.setLogin("");
this.setSenha("");
}

public String getLogin() {
return login;
}

public void setLogin(String login) {
this.login = login;
}

public String getSenha() {
return senha;
}

public void setSenha(String senha) {
this.senha = senha;
}

}
Role.java
/**
* Classe que representa uma role.
* @author Diego Fincatto
* @since 1.0
*/
public class Role implements Principal{

private String name;

public Role(String name){
this.name = name;
}

public String getName() {
return name;
}
}
User.java
/**
* Classe que representa um usuario.
* @author Diego Fincatto
* @since 1.0
*/
public class User implements Principal {
private String name;
private Set roles;

public User(String name){
this.setName(name);
}

private void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public Set getRoles() {
return roles;
}

public void setRoles(Set roles) {
this.roles = roles;
}
}






Configurações Necessárias
Primeiramente, precisamos criar um arquivo onde dizemos para a API de autenticação do Java que dispomos de um sistema de login personalizado. O mesmo é feito criando o seguinte arquivo, chamado login.config:
IF {
imagemfilmes.auth.IFLoginModule required
dataSourceName="imagem"
sqlUser="select senha from usuario where login=? and ativo = true"
sqlRoles="select role from usuario_roles where login=?"
bdDriver="org.postgresql.Driver"
bdUser="usuario"
bdPass="senha"
bdURL="jdbc:postgresql://ipdoservidor/banco"
;
};
Explicando rapidamente as opções do arquivo, o IF é o "nome" do modulo. imagemfilmes.auth.IFLoginModule são, respectivamente, o nome do pacote e da classe que fará a autenticação. Daí pra baixo são opções que serão passadas para o modulo de login para podermos trabalhar la dentro, como veremos mais adiante. Nada disso é necessário, embora seja interessante usar, pois, caso algum desses parametros mude, é só mudar as configurações desses arquivo e tudo volta a funcionar. Caso o desenvolvedor optasse por fixar dentro do código, a cada mudança seria necessário uma nova compilação e um novo deploy do arquivo.
OBS: Percebam que implementei no PostgreSQL.

Após a criação do arquivo, devemos dizer ao java que ele existe (pois o java não é pai de santo pra adivinhar né?). Fazemos isso editando o arquivo $JAVA_HOME/jre/lib/security/java.security. Adicionamos o nosso modulo de login ao arquivo de configuração, como na linha que segue login.config.url.1=file:/lugarondevocecriouoarquivo/login.config.

E para que a aplicação possa usar o modulo, dizemos pra ela que o faça, modificando seu contexto como segue:


Basicamente, adicionamos um Realm ao contexto, informando o tipo (classname), o nome da aplicacao, definido lá no login.config, e as classes de User e Role que foram implementadas (Vide capitulo da implementacao).

Socorro
Alguma coisa não está saindo como o esperado? Não se desespere!!! Para tudo nessa vida há alguma solução(embora na maioria das vezes nós não saibamos qual é a merda da solução!!!).
Você poderá debugar o seu módulo iniciando seu tomcat com os seguintes parametros:
-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n

Finalizando
E é isso pessoal, muita coisa pode ser feita para que se ajuste as nossas necessidades. O JAAS é uma API excelente, embora poucos desenvolvedores a usam (pelo menos como deveriam).

Créditos
Abaixo cito as fontes onde busquei inspiração para a resolução dos problemas de percurso encontrados.
  1. http://java.sun.com/products/jaas/
  2. http://www.guj.com.br/posts/list/38988.java

NetBeans com SVN em português

Há alguns dias estou trabalhando com um iMac (em outro post conto detalhes desta migração...) e estou ainda me adaptando.

Um problema encontrado, após a configuração do SVN, para utilização no NetBeans (que foi resolvida com esta dica) foram as mensagens de commit, que não podiam ter acentuação!
Sempre que colocava uma mensagem com acentuação, retornava uma mensagem de erro de commit "Can't convert string from native encoding to 'UTF-8'"...

Com algumas buscas, encontrei uma ajuda no livro do subversion, no capítulo de internacionalização, confirmei que o locale estava como C.
Ao definir o mesmo para pt_BR.UTF-8, com o comando export LC_ALL=pt_BR.UTF-8, esta definição ficava apenas para o terminal aberto.

A solução? Incluí esta linha no lançador do NetBeans, nano -w /Applications/NetBeans.app/Contents/Resources/NetBeans/bin/netbeans, e, voilà! Acentuação funcionando!

Alteração no post: apesar de ter baixado NetBeans em português, o mesmo sempre ficou em inglês... isto não era um problema, mas era, no mínimo, curioso. Com esta linha, agora o mesmo também ficou em português!

Segunda alteração: a idéia inicial era não afetar o sistema, apenas no NetBeans. Porém várias vezes uso o SVN no terminal, então colocar esta linha diretamente no /etc/profile é mais adequado...

terça-feira, 10 de abril de 2007

Calculando dígito verificador (DV) para contas da Caixa Econômica Federal (CEF)

Hoje me deparei com uma situação: estou fazendo uma integração com a CEF e muitas vezes tenho registros rejeitados pois o DV da conta está incorreto.

Minha primeira pergunta: como calculo o dígito verificador? Descobri, por contato telefônico, que é pelo módulo 11.
Desta forma, encontrei uma referência no Wikipedia. Porém, ao calcular, não batia (eu possuo poupança na CEF e serviu para testes...).
Após mais alguns passos no Google, achei uma referência interessante (role direto para a página 3). É necessário considerar, também, a agência e operação de conta!

Agora, com o algoritmo claramente definido, implementei a função em PostgreSQL (pl/pgsql), que ficou assim (a formatação foi perdida quando colei... mais tarde tento aprender a fazer isto):

CREATE OR REPLACE FUNCTION calculaDigitoCaixa(_dados varchar) RETURNS int2 AS $$
DECLARE
i integer;
peso integer;
base integer;
total integer;
resto integer;
dados varchar;
BEGIN
-- Verificar a consistência dos dados!
dados := COALESCE(_dados, '');
IF (LENGTH(COALESCE(_dados, '')) != 15) THEN
RAISE WARNING 'Dados não contém um tamanho válido! Tamanho: % Nulo: % Entrada: %', LENGTH(dados), _dados IS NULL, dados;
END IF;

peso := null;
total := 0;
-- Iniciar cálculo...
FOR i IN REVERSE LENGTH(dados)..1 LOOP
-- Qual peso?
IF (COALESCE(peso, 10) >= 9) THEN
peso := 2;
ELSE
peso := peso + 1;END IF;
-- Qual base?
base := SUBSTR(dados, i, 1)::int;

RAISE NOTICE 'Peso % * Base %', peso, base;
-- multiplica base * peso e acumula total
total := total + base * peso;
END LOOP;
RAISE NOTICE 'Total: %', total;
-- Multiplicar total por 10
total := total * 10;

-- O resultado então é o resto da divisão por 11. Caso seja 10, então é 0.
resto := total % 11;

RAISE NOTICE 'Resto: %', resto;
IF (resto = 10) THEN
resto := 0;
END IF;

RETURN resto;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

Coloquei a mesma IMMUTABLE, pois sempre haverá o mesmo retorno para uma mesma entrada (documentação)...

Agora basta validar, por exemplo:

SELECT calculaDigitoCaixa(agencia, operacao_conta, conta) FROM fornecedor ...
Primeiro post...

Nunca tive um blog, portanto esta será uma experiência interessante.
Vamos ver se conseguimos colocar à disposição de outros usuários soluções (ou problemas) que encontramos no dia-a-dia!

Até mais!