29 de mar de 2009

Monitoração de domínio e gravação de thread dump automático com WLST

Outro dia me deparei com um questionamento no fórum de discussão sobre como conseguir retirar os thread dumps do Servidor de aplicações, Oracle Weblogic, em momento oportuno, ou seja, quando o ambiente estiver passando por um momento de contingência. A discussão do problema pode ser vista detalhadamente no fórum do javaranch no link: http://www.coderanch.com/t/427054/BEA-Weblogic/Issue-with-WeblogicServer

Devido a este problema decidi escrever um artigo mostrando como podemos utilizar a linguagem de scripts do Weblogic Server, Weblogic Scripting Tool(WLST), para fazer monitoramento de servidores. Um ponto importante nestes script é que ele permite inclusive que este monitoramente seja feito de forma independente do Admin Server, pois neste caso, o script mostra conexão direta com servidores gerenciados de um domínio. Para escrevê-lo estou utilizando WLST que por sua vez utiliza linguagem Jython e é padrão para configuração do Oracle Weblogic.

O script:

O script demonstrado aqui é bem simples e o que ele faz basicamente é:

1) Carregar informações de um arquivo de propriedades.

2) Tenta conectar com cada um dos servidores da lista de servidores configurada no arquivo de propriedades.

3) Verifica status do servidor e caso o servidor estiver com um número maior que o definido de threads com delay na resposta gera um thread dump do servidor para posterior análise.

Abaixo segue o código do script comentado e logo em seguida um exemplo de arquivo de propriedades que pode ser utilizado como template.

from java.util  import Properties
from java.io  import FileInputStream
from java.io  import File

#============DEFINICAO DE FUNCOES============
#funcao que carrega dados de arquivo de propriedades
def carregaArquivoPropriedades(nomeArquivo) :
    print 'carregando propriedades do arquivo: ' + nomeArquivo
    #arquivo de propriedades a ser carregado
    localizacaoArquivoPropriedadesConfiguracao = nomeArquivo    
    myProps = Properties()
    #carrega arquivo de propriedades
    myProps.load(FileInputStream(File(localizacaoArquivoPropriedadesConfiguracao)))
    return myProps

#funcao que retorna lista de todos os servidores configurados para este domínio.
def getServidoresDominio():
    print 'executando funcao getServidoresDominio']
    domainConfig()
    servidores = cmo.getServers()
    return servidores

#funcao que pega lista de servidores como parametro e verifica o status de cada um deles.
def mostraStatusServidores(servidores): 
    print '=======================STATUS dos servidores do domínio==============='
    domainRuntime()
    for servidor in servidores:
        try:
            cd('/ServerRuntimes/' + servidor.getName())
            #ls()
            print servidor.getName() + ': ' + get('State')
        except WLSTException,e:
            servidoresNaoAcessiveis.append(servidor)
    servidoresAlerta = []
    #testa novamente servidores que não estava acessíveis para ter certeza
    for servidor in servidoresNaoAcessiveis : 
        try:
            cd('/ServerRuntimes/' + servidor.getName())
            #ls()
            print servidor.getName() + ': ' + get('State')
        except WLSTException,e:
            servidoresAlerta.append(servidor)
    if len(servidoresAlerta) > 0 :
        print 'ALERTA == ALERTA == ALERTA == ALERTA == ALERTA == ALERTA =='
        print 'Os seguintes servidores estão inacessíveis para monitoração, favor checar!'
        for servidor in servidoresAlerta :
            print servidor.getName()
            
#faz checagem de memória nos servidores do domínio especificado.
def listaConfiguracoesMemoriaServidoresDomino():
    servidoresComBaixoHeapMemoria = []
    for servidor in servidores:
        try:
            cd("domainRuntime:/ServerRuntimes/" + servidor.getName() + "/JVMRuntime/" +servidor.getName())
            heapSizeMax = cmo.getHeapSizeMax()/1048576
            heapMemoriaLivre = cmo.getHeapFreeCurrent()/1048576
            heapMemoriaLivrePercentagem = cmo.getHeapFreePercent()
            #adiciona na lista de servidores com pouca memoria se servidor tiver menos de 2% de memória livre
            if heapMemoriaLivrePercentagem < 2 :
                servidoresComBaixoHeapMemoria.append(servidor)
            #memoriaMB = memoria/1048576 #transforma os bytes em MB para mostrar
            print '\n================================================================='
            print "O servidor " + servidor.getName() + " esta com :"
            print 'Memoria total alocada(MB): ' + str(heapSizeMax)
            print 'Memoria total disponivel(MB): ' + str(heapMemoriaLivre)
            print 'Memoria livre(%): ' + str(heapMemoriaLivrePercentagem)
        except WLSTException,e:
            print 'AVISO: O servidor ' + servidor.getName() + ' nao esta acessivel atraves do admin server'
    #faz novo teste de heap de memória e caso continuem com pouca memória disponível, mostra ALERTA para observação do servidor.
    for servidor in servidoresComBaixoHeapMemoria :
        try:
            cd("domainRuntime:/ServerRuntimes/" + servidor.getName() + "/JVMRuntime/" +servidor.getName())
        except WLSTException,e:
            print 'AVISO: O servidor ' + servidor.getName() + ' nao esta acessivel atraves do admin server'
            heapMemoriaLivrePercentagem = cmo.getHeapFreePercent()
            #adiciona na lista de servidores com pouca memoria se servidor tiver menos de 2% de memória livre
            if heapMemoriaLivrePercentagem < 2 :
                print 'ALERTA == ALERTA == ALERTA == ALERTA == ALE RTA == ALERTA =='
                print 'O servidor ' + servidor.getName() + ' está com heap de memória < que 2% e deve ser observado!'
#faz checagem de threads dos servidores do domínio
def checaThreadsServidoresDominio() :
    servidoresComThreadsProblematicas = []
    for servidor in servidores :
        try:
            cd("domainRuntime:/ServerRuntimes/" + servidor.getName() + "/ServerChannelRuntimes/DefaultSecure[https]")
            numeroConexoes = cmo.getConnectionsCount()
            print '==============================================='
            print 'Dados do servidor ' + servidor.getName() + ': '
            print 'Conexoes https: ' + str(numeroConexoes)
            cd('domainRuntime:/ServerRuntimes/' + servidor.getName() + '/ExecuteQueueRuntimes/weblogic.socket.Muxer')
            fila = cmo.getPendingRequestCurrentCount()
            print 'Requisicoes de usuarios pendentes: ' + str(fila)
            cd('domainRuntime:/ServerRuntimes/' + servidor.getName() + '/ThreadPoolRuntime/ThreadPoolRuntime')
            hoggingThread = cmo.getHoggingThreadCount()
            print 'Quantidade de threads com status hogging: ' + str(hoggingThread)
            print '===============================================\n'
        except WLSTException,e:
           print 'Erro servidor não acessivel para ServerRuntimes ==>> ' + servidor.getName()

#faz health check nos pools de conexao do ambiente.
def checaPoolsConexoes() :
    domainConfig()
    #recupera lista de pools de conexões configuradas no domínio.
    connectionPools = cmo.getJDBCSystemResources()
    for pool in connectionPools : 
        print pool.getName()
        cd('domainConfig:/JDBCSystemResources/' +pool.getName()+ '/JDBCResource/' +pool.getName()+ '/JDBCConnectionPoolParams/' + pool.getName())
        print '==============================================='
        print 'Dados do pool: ' + pool.getName()
        capacidadeInicialPool = cmo.getInitialCapacity()
        capacidadeMaximaPool = cmo.getMaxCapacity()
        print 'Capacidade maxima do pool: ' + str(capacidadeMaximaPool)
        cd('domainConfig:/JDBCSystemResources/' + pool.getName())
        targetServers = cmo.getTargets()
        print 'targets do pool'
        for targetServer in targetServers :
            print targetServer.getName()
#=================FIM DEFINICAO DE FUNCOES======================
propriedades = carregaArquivoPropriedades('config.properties')
username = propriedades.get('username')
password = propriedades.get('password')
url = propriedades.get('url')
connect(username, password, url)
#lista para armazenar servidores não acessíveis através do admin server.
servidoresNaoAcessiveis = []
servidores = getServidoresDominio()
mostraStatusServidores(servidores)
listaConfiguracoesMemoriaServidoresDomino()
checaThreadsServidoresDominio()
checaPoolsConexoes()
disconnect()
exit()


E o arquivo de propriedades de exemplo:
#este arquivo de propriedades é utilizado para configurar os   
#servidores em um ambiente. Todas as chaves devem ter o formato  
#do nome utilizando sempre _ (underscore) pois é o que define a   
#busca dos nomes dos elementos e separa durante a configuarção   
#no script criaInstancias.py  
USUARIO_ADMIN=user  
SENHA_ADMIN=pwd  
   
PORTA_HTTPS_SERVIDORES=443  
   
#parametro que configura com que quantidade de threads com delay o thread dump deve ser tirado para o servidor.  
PARAMETRO_THREAD_DUMP=10  
   
#Dados dos servidores a serem monitorados pelo script  
SERVIDOR_1=server1  
IP_SERVIDOR_1=xxxxxx  
  
SERVIDOR_2=server2  
IP_SERVIDOR_2=xxxxxxx  
   
SERVIDOR_3=server3  
IP_SERVIDOR_3=xxxxxx  
   
SERVIDOR_4=server4  
IP_SERVIDOR_4=xxxxxx  
   
# .... you may add as many servers as you want here...  


Para este script ficar realmente funcional eu programaria para que ele ficasse conectado com os servidores por um período definido em ciclos e que verificasse o status de cada um de tempos em tempos(3 em 3min por exemplo). E caso o servidor apresentasse algum problema considerável dispararia uma rotina que seria responsável por tirar thread dumps com intervalo de cerca de 20s entre um e outro por um período de 2 min. Os thread dumps retirados seriam de extrema utilidade para definir qual o real problema com o ambiente.

[]s

26 de mar de 2009

Formatação de código-fonte para postagens no Blog

Fiquei algum tempo sem postar código fonte no blog pois como um blogueiro recente ainda não tinha conhecimento de como fazer para formatar o código fonte de uma maneira aceitável nos posts. 

Bem, como este é um blog técnico ficou impossível continuar dessa forma e portanto hoje resolvi pesquisar uma forma de fazer formatação de códigos fonte para postagens no blog. Pesquisando um pouco decidi primeiramente experimentar mais um produdo hospedado no Google code chamado SyntaxHighlighter http://code.google.com/p/syntaxhighlighter/  . A última versão(quei irei tratar neste artigo) migrou para http://alexgorbatchev.com/wiki/SyntaxHighlighter

Minha maior curiosidade é ver como uma linguagem como Jython, que uso muito no weblogic e tenho alguns posts aqui, vai ficar formatada imagino que java deve ficar bem bacana por ser mais comum.
Segue um passo-a-passo do que fiz para fazê-lo funcionar e alguns links de postagens deste blog já formatadas com este utilitário. 

O primeiro passo é baixar o pacote do projeto no link: http://alexgorbatchev.com/wiki/SyntaxHighlighter:Download
A última versão quando escrevo este é 2.0.296 .
O pacote contém um conjunto de javascript + css para formatação dos códigos.
Este conjunto deve ser disponibilizado na web para que possa ser acessado e essa foi minha primeira dificuldade, já estava pensando em fazer o upload para o ambiente que tenho contratado na locaweb(que por sinal é um excelente Hosting, não conheço melhor no Brasil) quando pesquisando a documentação do produto encontrei este link: http://alexgorbatchev.com/wiki/SyntaxHighlighter:Hosting
O criador do produto disponibiliza um repositório na web para acesso ao css e javascript e portanto vou testá-lo, se for o caso e eu sentir problemas de performance aí sim vou utilizar a Locaweb. Para utilizar o repositório disponibilizado nem havia necessidade de baixar o pacote!!!

O padrão para utilizar o hosting do autor, conforme documentação é:  http://alexgorbatchev.com/pub/sh/[VERSION]  e todas as versões disponíveis podem ser encontradas no link: http://alexgorbatchev.com/pub/sh/
Para utilizar o formatador o primeiro passo é declarar nas postagens desejadas o seguinte trecho de código que deve ser inserido no template de página no painel de administração do seu blog . No caso do blogger ir em Layout > Editar Html e colocar o javascript entre dentro da tag head do template, sugiro colocar imediatamente antes do fechamento da tag /head> depois salvar . (Eliminei tag de abertura html pois estava tendo problemas para mostrar!!! Alguém tem uma dica???): 

link type="text/css" rel="stylesheet" href="/styles/shCore.css">
link type="text/css" rel="stylesheet" href="/styles/shThemeDefault.css">
script type="text/javascript" src="/scripts/shCore.js">
script type="text/javascript" src="/scripts/shBrushJScript.js">
script type="text/javascript" src="/scripts/shBrushBash.js">
script type="text/javascript" src="/scripts/shBrushCpp.js">
script type="text/javascript">
syntaxhighlighter.all();</script>

Importante lembrar, e o autor do produto cita isso, que os caracteres de tag html e xml devem ser corretamente substituídos:

< por &lt;
> por &gt; (ok.. ok.. esse não é obrigatório mas é uma boa prática).
Outra coisa é que se for usar o repositório disponibilizado deve-se mudar as referências passando o caminho completo, ex: 

link type="text/css" rel="stylesheet" href="/styles/shCore.css">
Fica para versão 2.0.296: 
link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/2.0.296/styles/shCore.css">
Lembrem-se que retirei a tag de abertura &lt 
e assim segue para todas as referências.

Feito isso deve-se usar tags pre de html para formatar os códigos desejados e definir o que o autor chama de Brush relacionando ao padrão de fontes que está sendo formatado (java, javascript, etc).
Ver lista completa em: http://alexgorbatchev.com/wiki/SyntaxHighlighter:Brushes
Exemplo formatação javascript: 

pre class="brush: js">alert("Hello world")/pre>
Um link em que já utilizo o recurso como referência: 
http://mmaiacupofcoffee.blogspot.com/2009/03/jme-implementacao-de-api-para.html
P.S - Para cada brush que você decidir utilizar tem um javascript diferente que deve ser carregado.

P.S2 - Implementei em todo o blog a formatação de código. Deu um trabalho considerável(umas 4 horas para revisar cerca de 30 posts, ainda bem que sou blogueiro mirim ainda!!!!) pois tive que desabilitar a quebra automática de linha em Configurações > Formatação > Converter quebras de linha tive que colocar não pois caso contrário a ferramenta de edição deste blogger colocava automáticamente quebras de linha(br) nos códigos!!!
[]s

24 de mar de 2009

Appfuse - Utilizar tooltip do struts 2 causa um erro com Dojo

Recentemente um problema simples me tomou algumas horas de pesquisa e o problema, como usual, era simples de ser resolvido.
Utilizando Struts 2 do Appfuse para desenvolvimento de uma aplicação quando colocava um tooltip no formulário percebia um erro mostrado pelo firebug no firefox o tooltip era:


E o erro mostrado pelo firebug:
dojo is not defined:dojo.requ...);dojo.require("dojo.fx.html"); 

Fiz uma postagem na lista de discussão do appfuse em : http://www.nabble.com/Using-struts-2-tooltip-causes-error!-td22669446s2369.html
E a solução do problema foi bem simples e envolve 2 passos:
1) Mudar a extensão do mapeamento do struts 2 de .html que é o default do appfuse pois isso causa conflito com dojo. (Esse passo eu já havia feito no meu projeto).
2) Adicionar a tag s:head do struts ao head html da página.
O problema foi resolvido, no meu caso, só com a s:head adicionada. Bem simples e me tomou um tempo considerável.
[]s

23 de mar de 2009

Ubuntu - Dicas de configuração de ambiente - Instalação Mysql, Maven e Efeitos Desktop

Este final de semana instalei o Ubuntu 8.10 no meu desktop para utilizar como ambiente de trabalho e desenvolvimento de software. Durante a instalação encontrei algumas dificuldades básicas que me tomaram algum tempo e por isso segue aqui algumas dicas e links de sites de como eu resolvi tais problemas para futura referência.

Instalação do Mysql, Mysql Admin Tools e Maven - A melhor forma de instalar o Mysql que encontrei foi utilizando a ferramenta Synaptic Package Manager(System > Administration > Synaptic Package Manager). Basta procurar por Mysql na busca da ferramenta, selecionar o que deseja instalar, e pronto, bem prático. Já para instalar o maven basta abrir um console e digitar sudo apt-get install maven2 aguarde os pacotes e dependências serem baixados e instalados configure o caminho para seu repositório em : /usr/share/maven2/conf/settings.xml e pronto o Maven está pronto para usar. Veja o vídeo ilustrativo da instalação do maven em: http://www.screencast.com/t/eeP2P8jws3

Configuração do Mysql - Um problema que senti assim que tentei utilizar o mysql é que não conseguia fazer conexão das ferramentas de administração. Isso acontece porque por default ele é habilitado para escutar conexões somente no localhost(127.0.0.1). Para mudar isso editar o arquivo: /etc/mysql/my.cnf e comentar a linha onde aparece: bind-address:127.0.0.1
Depois reiniciar o mysql com o comando: mysql restart

Habilitar efeitos 3D no Ubuntu - Por último uma coisa opcional mas bem legal é a instalação do pacote de efeitos de Desktop no Ubuntu o que vai dar visual mais legal e efeitos 3D(cubo) no O.S . Para fazer a instalação é bem fácil, utilizando o Synaptic Package Manger basta procurar por compizconfig-settings-manager e depois utilizar o menu do Ubuntu em System> Preferences> ConpizConfig Settings Manager para acessar o painel de configurações de efeitos, são vários, bem legal!

[]s

22 de mar de 2009

Como instalar um pacote RPM no Ubuntu Linux

Assim que instalamos o Ubuntu e começamos a baixar os pacotes de programas para utilizar com ele nos deparamos com a necessidade de instalar pacotes no formato RPM pois alguns programas ainda disponibilizam somente pacotes com esta extensão que não é imediatamente reconhecida e executada pelo Ubuntu.

Por isso segue uma lista com instruções rápidas de execução de arquivos RPM no Ubuntu.

Primeiramente tem que instalar o Alien que é utilizado para conversão de formatos de arquivo no linux:

sudo apt-get install alien dpkg-dev debhelper build-essential

Aguarde o download dos pacotes que deverá iniciar. Para transformar o pacote desejado para o formato reconhecido pelo Ubuntu utilize o comando:

sudo alien NOME_DO_PACOTE.rpm

Esse comando levará algum tempo e crirá um pacote no mesmo diretório chamado NOME_DO_PACOTE.deb Para instalar o pacote utilize o utilitário dpkg

sudo dpkg -i NOME_DO_PACOTE.deb

Pronto, se o pacote for compatível com Ubunto ele será instalado.

[]s

21 de mar de 2009

Configuração do ambiente de desenvolvimento

Quando formato o computador ou instalo um novo sistema operacional(Neste momento estou instalando Ubunto 8.10 para trabalhar no desktop em casa) para iniciar o meu trabalho é sempre chato ficar procurando os links para baixar tudo o que é necessário e útil para o dia a dia.

Atualmente utilizo o Appfuse para desenvolvimento e portanto a lista contém o necessário para utilizá-lo além de outras ferramentas úteis.

É bem desagradável quando só percebemos que precisamos de um determinado plugin do eclipse ou ferramenta indispensável quando efetivamente precisamos dela e percebemos que ainda temos que baixar, configurar, etc. Por isso estou colocando aqui uma lista de todas as principais ferramentas e plugins que utilizo para trabalhar para futuramente servir de ponto de partida para a montagem de um novo ambiente de trabalho.

No Ubuntu é bom lembrar que podemos facilmente instalar muitas coisas utilizando o utilitário Synaptic acessado do menu principal do Ubuntu: System > Administration > Synaptic Package Manager

JDK - http://java.sun.com/javase/downloads/index.jsp

Java ME Toolkit da Sun(Desenv. JME) - http://java.sun.com/products/sjwtoolkit/download.html

MySQL - http://dev.mysql.com/downloads/

Maven - http://maven.apache.org/download.html

m2e (Maven plugin para Eclipse) - http://maven.apache.org/eclipse-plugin.html

Eclipse Europa (Versão que uso atualmente) - http://www.eclipse.org/europa/

Eclipse (última versão) - http://www.eclipse.org/downloads/

Eclipse ME(Eclipse plugin) - hhttp://www.eclipseme.org/

Floggy (API Java ME) - http://www.floggy.org

MicroLog (API Java ME) - http://microlog.sourceforge.net

Eclipse plugin de cliente SVN - http://subclipse.tigris.org/

SMTP server - http://james.apache.org/

Tortoise(cliente de Subversion para Windows somente) - http://tortoisesvn.net/downloads

Web developer toolbar (Firefox plugin) - https://addons.mozilla.org/en-US/firefox/addon/60

Delicious bookmars(Firefox plugin) - https://addons.mozilla.org/en-US/firefox/addon/3615

Fire FTP(Firefox plugin) - https://addons.mozilla.org/en-US/firefox/addon/684

FireBug (Firefox plugin) - https://addons.mozilla.org/en-US/firefox/addon/1843

Execute JS (Firefox plugin) - https://addons.mozilla.org/en-US/firefox/addon/1729

Quick locale switcher (Firefox plugin) - https://addons.mozilla.org/en-US/firefox/addon/1333

Free mind - http://freemind.sourceforge.net/wiki/index.php/Download

Jude (Ferramenta UML para windows somente) - http://jude.change-vision.com/jude-web/download/index.html

Bouml (Ferramenta UML Linux) - http://bouml.free.fr/download.html

Oracle Weblogic Server - http://www.oracle.com/technology/software/products/ias/bea_main.html

[]s

20 de mar de 2009

Software de virtualização gratuito - Virtual Box

Estou precisando rodar outros ambientes virtualizados no windows para poder demonstrar features do weblogic e usar o software de captura de tela que utilizo que é o Jing. As versões do Jing disponíveis atualmente só rodam em windows ou Mac e portanto para demonstrar outros sistemas operacionais decidi utilizar um programa de virtualização. 

Já utilizei profissionalmente o VMWare Server  que é uma ótima ferramente mas como estou procurando algo gratuito  e para uso pessoal optei por baixar e testar o Virtual Box da sun, segue o link: http://www.virtualbox.org/

Vou testá-lo e posteriormente coloco minha impressão sobre este software pois é a primeira vez que irei utilizá-lo. Os sistemas operacionais no meu desktop em casa são o Windows XP 64bits e o Ubuntu linux 10 64 bits. Vou rodar o virtual box no Windows.


[]s

19 de mar de 2009

Oracle Weblogic Server Tutorial. Parte 1 - Instalação Windows

A instalação do weblogic server é bem simples, a idéia deste post é fazer um quick start bastante resumido. O link para a documentação oficial de instalação da versão Weblogic 10.3, que é a mais recente  e completa, é: http://download.oracle.com/docs/cd/E12840_01/wls/docs103/sitemap.html

A primeira coisa é baixar o pacote compatível com o sistema operacional que estiver utilizando, para baixar os pacotes veja o link:  http://www.oracle.com/technology/software/products/ias/bea_main.html

Nesta série sobre configurações básicas no weblogic que estou iniciando irei fazer tutoriais em vídeo. A ferramente é o Jing conforme descrevi em outro post: http://mmaiacupofcoffee.blogspot.com/2009/03/documentacao-de-sistemas-demonstracao.html

Vou demonstrar instalação em um ambiente windows. Vou mostrar o modo de console gráfico para todas as configurações deste tutorial, posteriormente pretendo fazer o mesmo tutorial sem utilizar o modo gráfico no linux.
No windows o processo de instalação é todo gráfico com wizards o que torna tudo bem intuitivo para o usuário. O windows que estou utilizando para estas demonstrações é Windows XP.

Para ver o vídeo da primeira parte deste tutorial que mostra a instalação do Oracle Weblogic Server 10.3 acesse o link abaixo(O instalador já deve ter sido baixado!): 


[]s

18 de mar de 2009

Struts 2 - Customizando elementos de form

Esta semana precisei fazer uma customização no padrão de forms que utilizo. Basicamente o que estava ocorrendo era que eu precisava mudar o padrão de mensagens de erro do struts 2 utilizando o tema xhtml para não aparecer a mensagem de erro no campo diretamente só em uma lista em cima do formulário desejado e com um ícone mostrando o campo no form. 
Fiquei mais uma vez muito satisfeito com a solução do struts 2 para definição destes padrões. Basicamente o struts 2 utiliza uma estrutura de templates e temas que nos dá uma enorme flexibilidade na manipulação destes forms. A documentação do struts tem várias informações sobre isso nos links: 


Como não conheco linguagens de templates eu levei cerca de 3 horas e 30 minutos entre o início da minha pesquisa para modificar os templates até conseguir o que queria. 
Como ainda não tive tempo para colocar uma formatação decente para apresentação de código fonte, principalmente html, deixo aqui o link do fórum do javaranch onde iniciei um tópico de discussão sobre este assunto e postei todo o código e procedimento que adotei até conseguir chegar a uma solução final, tá tudo explicado lá no fórum(em inglês). 
Basicamente o que mudou com este código foi do seguinte padrão(imagem abaixo): 
No final ficou no seguinte padrão(imagem abaixo):
Struts 2 rocks!
[]s

16 de mar de 2009

Documentação de sistemas, demonstração de bugs, Software de captura de tela - Jing

Essa é uma dica rapidinha. Estive procurando por alguns dias um software de captura de telas para utilizar na documentação de sistemas e demonstração de bugs de software. Depois de alguma procura encontrei um site com uma enorme lista: http://www.c4lpt.co.uk/Directory/Tools/capture.html
e alguns testes depois cheguei ao Jing que definitivamente me pareceu a melhor opção. Funciona muito bem e é muito intuitivo e fácil de começar a utilizar. Pode ajudar muito na comunicação entre uma equipe, documentação de sistema e demonstração de bugs. A versão gratuita funciona muito bem e já atende a maioria dos projetos. Vale a pena conferir:

[]s
 
 

11 de mar de 2009

JME - Implementação de API para persistência de dados Floggy

Hoje finalmente encontro tempo para começar a fazer a migração da minha aplicação para utilizar a Floggy que é uma API de persistência para Java ME criada por brasileiros, mais detalhes em : http://floggy.sourceforge.net/ 

O primeiro passo foi fazer a instalação do plugin para eclipse conforme descrito na documentação em: http://floggy.sourceforge.net/configuration/eclipse.html

A url para o eclipse é: http://floggy.sourceforge.net/eclipse e o plugin foi baixado corretamente e a versão instalada foi a 1.2.0 conforme a imagem abaixo:

Após isso, seguindo as instruções,  reiniciei o eclipse. Depois para adicionar as dependências ao meu projeto no eclipse foi só clicar com o botão direito sobre o projeto e selecionar Floggy > Add Floggy nature. Isso adicionou uma nova dependência ao meu projeto apontando para a library da Floggy, conforme imagem abaixo: 
Tudo bem tranquilo, sem nenhum problema. Lembro que no meu ambiente de desenvolvimento estou utilizando Eclipse Europa 3.3.2 com plugin do Eclipse ME: http://eclipseme.org/

Agora com o ambiente configurado estou pronto para iniciar o refactoring do código para substituir as chamadas diretas da API RMS pela utilização da API Floggy.

Para fazer a implementação estou seguindo os passos conforme documentação em: http://floggy.sourceforge.net/getting-started.html

A primeira coisa interessante que notei estudando os guias da API foi que irei retirar uma camada que existe atualmente no meu projeto destinada a persistência. No meu padrão de desenvolvimento JME eu defini uma camada RMS em um pacote conforme a figura abaixo:
Neste pacote eu defini uma classe base para todas as classes responsáveis pela persistência que é a classe AbstractDBME e para  user story do meu sistema eu implementava uma respectiva classe DBME conforme a imagem acima.  Estas classes são responsáveis pela persistência utilizando RMS onde existe código como: 

/**
* método que persiste o registro do login na base de dados local do device.
*
* @param loginME
*            inicializado e com parâmetros carregados.
*/
public void adicionaLogin(LoginME loginME) {
  log.debug("Entrou LoginDBME.adicionaLogin()");
  try {
    int idLoginME = baseDados.getNextRecordID();
    loginME.setId(idLoginME);
    byte[] b = loginME.toByteArray();
    baseDados.addRecord(b, 0, b.length);
  } 
  catch (Exception ioe) {
    ioe.printStackTrace();
  }
  log.debug("Executou LoginDBME.adicionaLogin()");
}

/**
* atualiza status do usuário ativo na base de dados. Somente um usuário
* ativo deve existir por vez em um device.
* 
* @param idLogin
*            o id
*/
  public void setAtivo(int idLogin) {
    log.debug("Entrou LoginDBME.setAtivo() setar para ativo o login " + idLogin);
    ObjectSet logins = recuperaRegistros();
    try {
      for (int i = 0; i < logins.size(); i++) {
 LoginME loginME = (LoginME) logins.get(i);
 // garante que somente o id passado estará como true.
 if (loginME.getIdUsuario() == idLogin) {
   log.debug("Setando para ativo o login ==>> " + loginME.getLogin() + " idUsuario: " + loginME.getIdUsuario());
   loginME.setAtivo(true);
   baseDados.save(loginME);
 } else{
   log.debug("Setando para inativo o login ==>> " + loginME.getLogin() + "idUsuario: " + loginME.getIdUsuario());
   loginME.setAtivo(false);
   baseDados.save(loginME);
 }
    }
  } catch (Exception e) 
  {
    log.error(e.getMessage());
    e.printStackTrace();
  }
    log.debug("Executou LoginDBME.setAtivo()");
}

No código original existem estes além de muitos outros métodos similares e no meu ponto de vista, mais complexos do que deveriam, o que dificulta muito a evolução e manutenção do meu sistema. 
 
A minha grande expectativa é que utilizando Floggy todo este pacote deixe de existir no meu projeto eliminando esta complexidade desnecessária.

Pelo que percebi a Floggy trabalha com um modelo de persistência muito parecido com o do hibernate e portanto o primeiro passo foi definir as classes do meu modelo que encontram-se no pacote br.com.maweb.controlepeso.jme.model e que são pojos simples com a única diferença que, para atender a uma demanda do RMS, eu havia implementado um padrão onde cada classe do meu modelo tinha a responsabilidade de serializar e recuperar as informações através de métodos fromByteArray e toByteArray. 
Exemplo da implementação nos pojos: 

public void fromByteArray(byte[] dados) throws IOException {
  log.debug("Entrou LoginME.fromByteArray");
  ByteArrayInputStream bin = new ByteArrayInputStream(dados);
  DataInputStream din = new DataInputStream( bin );
  this.id = din.readInt();
  this.idUsuario = din.readInt();
  this.login = din.readUTF();
  this.password = din.readUTF();
  this.ativo = din.readBoolean();
  log.debug("ControlePesoME.fromByteArray()" + this.toString());
  din.close();
  log.debug("Executou LoginME.fromByteArray");
}
public byte[] toByteArray() throws IOException {
  log.debug("Entrou LoginME.toByteArray");
  ByteArrayOutputStream bout = new ByteArrayOutputStream();
  DataOutputStream dout = new DataOutputStream( bout );
  dout.writeInt(getId());
  dout.writeInt(getIdUsuario());
  dout.writeUTF(getLogin() );
  dout.writeUTF(getPassword());
  dout.writeBoolean(isAtivo());
  dout.close();
  log.debug("Dados retornados em array de bytes ==>> Id: " + getId() + ", ativo: " +  isAtivo()); 
 log.debug("Executou LoginME.toByteArray");
 return bout.toByteArray();
}

Essa implementação também deixou de ser necessária após a completa implementação da API Floggy, simplificando bastante o meu código.

Continuando com a implementação a primeira coisa que fiz foi retirar a referência para a interface de marcação que eu utilizava nos meu POJOs do device para garantir a implementação dos métodos toByteArray e fromByteArray que eu utilizava para persistência direta com RMS,retirada a interface e os métodos fromByteArray e toByteArray minha classe ficou então definida somente com os atributos e respectivos getters e setters para as propriedades.

Esta alteração causou problemas na classe de persistência que utilizava o método para fazer a persistência do objeto com RMS em rotinas como: 
byte[] b = loginME.toByteArray();
baseDados.addRecord(b, 0, b.length);

Este problema deverá ser resolvido substituindo as rotinas de persistência por chamadas de persistência da API Floggy.
Como mostra o fragmento de código acima eu tinha na minha classe LoginDBME uma referência RecordStore denominada baseDados o que fiz foi mudar esta referência para utilizar o PersistableManager da Floggy.
Também retirei as chamadas a métodos como conectaBase e fechaConexao o que deixou o código bem mais limpo.
Durante o procedimento tive que corrigir vários erros de compilação que apareceram e adaptar vários métodos que utilizavam API RMS.
Um dos pontos a destacar foi a alteração do método que recupera os registros que retornava um RecordEnumeration com todos os registros e agora retorna um ObjectSet com objetos do tipo desejado, isso possibilitou também que eu removesse outros métodos.

No final o que posso dizer é que o processo de implementação no meu caso de uso  não foi complexo, levou cerca de 2 horas de trabalho para acertar todas as arestas e o resultado final me agradou MUITO pois simplificou muito a manutenção e evolução do sistema além de ter diminuído considerávelmente a quantidade de código demandada para persistência e esse tempo de implementação com certeza será recuperado pela simplificação da manipulação da camada de persistência.

Pelo pouco que pude ver e fazer com a API recomendo a utilização da API  Floggy, sem sombra de dúvidas. Vale a pena!
Agora é implementar nos outros módulos do meu sistema.

[]s

P.S - O único problem que tive foi que a configuração da Floggy "desmarcou" no java build path do meu projeto eclipse a API MicroLog que também utilizo no projeto. Isso fez com que eu ao tentar testar tomasse erro de ClassNofFound apesar da API Microlog estar add no java build path. O que tive que fazer foi selecionar a aba Order and Export e selecionar novamente a API micrologger para ser incluída no meu pacote e tudo voltou a funcionar normalmente.

10 de mar de 2009

Weblogic - Travamento ao clicar no Activate do Admin Console

Hoje foi um dia muito corrido no trabalho, trabalhei bastante e não deu tempo de implementar a API de persistência e nem trabalhar no módulo Struts. Começei a escrever um tópico sobre upload no struts 2 que devo terminar amanhã.

Vou então deixar uma dica rápida relativa ao weblogic 10.X. No admin console depois de clicar em Lock & Edit e editar as altarações que deseja e voltar em clicar em Activate o console trava, fica processando e nada acontece. É um erro que infelizmente vem ocorrendo com certa frequência no trabalho do dia a dia com weblogic. 
São 2 as principais e mais usuais causas deste tipo de problema: 

1) Quando o domínio do weblogic é distribuído em mais de um hardware e está configurado para conectar no nodemanager e este não está funcionando corretamente.

2) Quando alguma permissão no diretório de instalação do weblogic ou do domínio perderam a permissão de escrita ou direito de apagar arquivos, renomear etc... Isso é comum quando, por exemplo, em qualquer ambiente unix ou derivado é criado um usuário e um grupo para o weblogic como: weblogic:weblogic e alguém editou ou manipulou algum arquivo como root retirando a permissão do usuário. Isso faz com que o console tenha o mesmo comportamento de impossibilidade de ativar as alterações.

As situações acima são as que mais comumente causam o problema do aparente "travamento" ao clicar em Activate, na verdade não trava o console mas o activate nunca consegue completar. O chato desta situação é que o console não mostar nenhuma mensagem e também nada sai no log do Admin console informando o que está causando o problema, o que dificulta muito descobrir o que está acontecendo.
Fica esta dica e lembrete sobre o problema. 
[]s

Struts 2 - Como fazer upload

Segue um passo a passo de como fazer upload utilizando o Struts 2. A documentação oficial sobre este assunto pode ser encontrada em : http://struts.apache.org/2.1.6/docs/handling-file-uploads.html .  O processo é bastante simplificado pois o Struts 2 utiliza um Interceptor (fileUpload)  e a librarie Jakarta Commons FileUpload, esta semana precisei revisar este tópico, então segue aqui um rápido passo a passo:
1) A primeira coisa é mudar o s:form adicionando o enctype, fica assim: 

O que possitilita o upload é a entrada: enctype="multipart/form-data" que foi adicionado no form.

2) Utilizar um campo s:file no jsp
s:file name="foto" label="Sua foto"

3) Criar uma Action para receber a requisição. E registrá-la no struts.xml, ou conforme o tipo de configuração que estiver utilizando, o struts 2 tem um plugin "Zero Configuration" ou pode utilizar anotations também como opções. Como estamos utilizando o Interceptor para fazer o upload tudo o que tive que fazer na action foi declarar as seguintes propriedades e seus respectivos métodos setXXX

private File foto;
private String fotoFileName;
private String fotoContentType;

4) No método da action para tratar o arquivo escrevi o seguinte código: 
//pega ServletContext para definir um diretório para a foto.
   ServletContext sContext = ServletActionContext.getServletContext();
   //checa se o arquivo não é nulo.
   if(foto != null)
   {
    //direciona as fotos para este diretório.
    String diretorioFotos = sContext.getRealPath("/WEB-INF/fotos");
  
    //Cria o diretório se o mesmo não existir.
    File dirPath = new File(diretorioFotos);
       if (!dirPath.exists())
       {
        log.debug("diretorio nao existe criando==>> " + diretorioFotos);
           dirPath.mkdirs();
       }
  
       //salva a foto com o nome do e-mail do usário para evitar duplicidade.
    File arquivoSalvo = new File(diretorioFotos, getRequest().getSession().getAttribute("email").toString() + "." + getExtensaoArquivo());
  
    foto.renameTo(arquivoSalvo);
    log.debug("Content type: " + fotoContentType);
   }

E pronto, este é o processo básico para upload utilizando Struts 2 . Não entrei em detalhes de configurações que podem ser feitas como : tamanho máximo de arquivo, extensões válidas, etc. Para mais informações sobre estas questões ver as referências no site do struts 2 em(versão 2.1.6): 

e

9 de mar de 2009

JME - Implementação de Base de Dados para Device Floggy

Depois de vários dias pesquisando e debatendo em fóruns as alternativas de persistência em devices para Java ME decidi implementar a Floggy que é uma API que encapsula o RMS do Java ME tornando a manipulação e persistência destes dados mais simples. O que percebi nestes últimos dias foi que não consegui debater muito a fundo a utilização de base de dados ou deste tipo de API para JME por não ter encontrado ninguém com experiência disponível para um debate mais profundo nos fóruns e internet. Pesquisei em blogs, fóruns e encontrei muito pouca informação  e por isso ainda com um pequeno receio pela minha pouca experiência em JME decidi implementar a Floggy no meu projeto.
 
Um dos principais motivos que me levou a escolher a Floggy é que ela é um projeto de Brasileiros, o que me deixa muito contente. O link oficial desta API é http://floggy.sourceforge.net/ e nas próximas linhas irei detalhar os passos que segui para implementação deste Framework.

Uma primeira coisa que me agradou bastante e veio de encontro ao que preciso foi a disponibilidade de instalar como um plugin do eclipse, conforme instruções no link:  
Oooops... Encontrei um problema, a versão atual da Floggy conforme descrito no site no dia de hoje e que baixei manualmente é a versão 1.2.0 e a versão disponível no plugin do eclipse é a versão 1.1.3 e por isso suspendi a instalação através do plugin do eclipse e estou procurando alternativas para utilizar a última versão via eclipse. 

Vou tentar fazer um post na lista de discussão da Floggy sobre o problema e espero resolver a questão em breve para poder dar continuidade a este projeto de implementação da API. Portanto momentâneamente vou suspender a utilização mas pretendo, ainda esta semana, voltar a este ponto pois estou sentindo forte necessidade, conforme já descrito em outros posts, de simplificar o processo de utilização de persistência nos devices e o RMS não está atendendo às minhas expectativas. Assim que eu retomar esta implementação no meu projeto irei complementar este post com minhas impressões e o procedimento executado para implementar a Floggy.


E devido a este problema estou retomando os estudos das opções disponíveis, mas ainda inclinado a utilizar a Floggy mesmo. Infelizmente não posso postergar mais que uma semana esta questão para não atrasar o meu projeto então até o final da semana farei outro post sobre minha decisão final e o feedback da lista de discussão da Floggy.

IMPORTANTE - A resposta no fórum e solução do problema pelo time do projeto Floggy foi bem rápido(em cerca de 2 horas) , o que me dá bastante confiança na utilização da Floggy. Fique MUITO satisfeito com a rápida solução do problema pelo time do projeto e amanhã irei fazer um novo post sobre o passo a passo da implementação no meu projeto pois hoje estou sem mais tempo hábil. Por ser um projeto bastante ativo e pela ótima resposta que tive no fórum irei mesmo utilizar essa API. Parabéns aos envolvidos no projeto. Fico muito contente em conhecer mais um projeto Open Source promissor desenvolvido por um time Brasileiro.

[]s

8 de mar de 2009

JME - Implementação API MicroLog para devices

Iniciei a implementação da API de log para devices MicroLog em um projeto. Vou colocar aqui como foi a experiência e minhas considerações até o momento.

Para desenvolvimento JME estou utilizando o Eclipse Europa 3.3.2 com plugin EclipseME www.eclipseme.org e portanto vou focar nesta configuração:

1) Baixei o pacote do MicroLog no link: https://sourceforge.net/project/showfiles.php?group_id=138008&package_id=277155&release_id=664332 a versão .zip para utilizar no windows.

2) Criei uma entrada no projeto no eclipse : botão direito > properties > java build path uma librarie com o jar do microlog. (imagem)  microlog-logger-1.1.1-me.jar.

Feito isto as APIs da MicroLogger que eu queria utilizar já estavam disponíveis no meu projeto JME no eclipse. 

3) Criei um arquivo chamado microlog.properties mínimo conforme documentação para configurar o logger que vou utilizar. Coloquei este arquivo na pasta "res" do meu projeto JME no eclipse. Neste arquivo somente as entradas de configuração mínima: 

microlog.level=DEBUG
microlog.appender=net.sf.microlog.appender.ConsoleAppender
# End of file. Do not remove this line.

4) Alterei o código do midlet adicionando 2 variáveis estáticas:
private static final Logger log = Logger.getLogger(LoginMidlet.class);
private static boolean firstTime = true;

E no método startApp do midlet: 

// Configura para carregar propriedades da api MicroLog só uma vez
if (firstTime) {
  Properties properties = new Properties(this);
  log.configure(properties);
  log.info("startApp() primeira vez");
  firstTime = false;
  } 
else {
  log.info("startApp() novamente");
  }

Isso foi o necessário para configurar um log básico, nos métodos eu pude então utilzar chamadas normais no log. 

log.debug("texto do debug aqui!!!");

5) Nas classes utilizadas no midlet bastou então definir a variável estática, por exemplo: 
//api de log
private static final Logger log = Logger.getLogger(LoginDBME.class);

E pronto, pude utilizar as chamadas de log padrão na classe. Bem simples e a utilização é bem parecida com o Log4j inclusive as saídas no console do WLTK. 

O mais interessante é que esta API dá opções de envio via sms, http, smtp, vale a pena dar uma olhadinha na documentação e nos exemplos.
 Segue o link mais uma vez: http://microlog.sourceforge.net/site/

[]s

7 de mar de 2009

JME - API de log para devices

Durante meu trabalho com Java ME outra necessidade que logo senti foi uma api de log para o projeto, System.out nunca é uma boa opção . Esta foi mais fácil já defini que irei utilizar a MicroLog que, apesar de novo e com pouca documentação, me parece um projeto bem consistente e em atividade. No projeto estou utilizando MIDP 2.0 e CLDC 1.1 esta última pré-requisito para utilização da MircoLog. Se estiver utilizando CLDC 1.0 ela não é compatível(pelo menos é o que está  descrito na documentação). 
[]s

JME - Lista de Bases de Dados

Devido a algumas limitações conforme descrito na documentação da base de dados Floggy que estive analisando decidi postergar e estudar melhor as opções. Encontrei uma boa lista no fórum do javaranch, no link: http://www.coderanch.com/t/230853/Java-Micro-Edition/Mobile/List-Database-J-ME
Após um dia inteiro de leitura e análise das opções ainda estou entre 2 : A Floggy  já mencionada e que é feita por Brasileiros o que é muito legal e a Perst Lite. Preciso resolver ainda esta noite pois tenho urgência no meu projeto. Descartei algumas da lista citada acima por não serem orientada a objetos e por inatividade nos respectivos projetos.
[]s

3 de mar de 2009

JME - RMS Como fazer os dados persistentes durante o desenvolvimento

Estou trabalhando em um projeto que envolve Java ME e me deparei com um problema, que acredito, seja bastante comum. Durante o desenvolvimetno senti a necessidade de que a base de dados de testes para o emulador JME do device fosse persistente e não fosse recriada para cada vez que eu tiver que executar o client para testes.

Explicando melhor,  é o caso, por exemplo que enfrento no momento. Na aplicação o usuário deve se autenticar na primeira vez que for utilizar o device para iteragir com o servidor, neste momento faço a persistência do usuário, caso a autenticação seja OK, no device, para que nas próximas vezes o usuário não tenha que se autenticar novamente. 
Posteriormente quando  o usuário vai fazer alguma outra operação do sistema recupero o usuário já autenticado e ativo no device para associar a operação sendo executada com o usuário corretamente. 
O problema é que durante o desenvolvimento como o midlet de login e de outras operações são codificados separadamente a base de dados não contém mais o usuário autenticado o que causa um NullPointerException em uma rotina para recuperar o usuário similar a: 

// recupera usuario ativo no device.
LoginDBME loginDBME = new LoginDBME(true);
int idUsuario = loginDBME.getLoginAtivo().getIdUsuario();


Isso tem se mostrado bastante frustrante durante o desenvolvimento e por isso preciso encontrar um meio de fazer com que a base de dados do emulador de device(utilizo o da sun) fique permanentemente armazenada no meu computador. 

Pesquisei muito sobre esta questão e infelizmente não consegui achar nada realmente útil na internet. A única solução que encontrei para o problema foi encontrar a base de dados temporária gerada pelo emulador, no meu caso no windows logado como Administrador se encontrava no C:\Documents and Settings\Administrator\j2mewtk\2.5.2\appdb onde é criada uma pasta com nome temp.DefaultColorPhonexx .
Após localizar a base o que fiz pode-se dizer que foi um "gato" ou POG(programação orientada a gambiarras) tendo eu que locar o arquivo para que quando o emulador fosse fechado não tivesse permissão para apagar o mesmo. 

Para mim essa não é uma solução aceitável e devido a este e a vários outros problemas com o desenvolvimento utilizando RMS decidi começar a avaliar a utilização de uma base de dados para devices(JME) . Meus requisitos para utilização são portabilidade e que a mesma seja gratuita. Inicialmente estou estudando a Floggy: http://floggy.sourceforge.net/ e provavelmente irei refatorar meu código para utilizá-la. Deixarei aqui posteriormente minhas impressões sobre ela.


FINALMENTE UMA SOLUÇÃO (DATA 31/03/2009)
Hoje finalmente encontrei uma solução bastante simples e já disponível no WTK 2.5.2 que estou utilizando. O que deve ser feito é abriar o WTK e ir em Edit > Preferences > Storage e nesta aba preencher a pasta onde se quer colocar a base de dados do device no campo: Storage root directory . Isto irá fazer com que a configuração seja persistente não mais utilizando as bases temporárias default do WTK.