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.

Nenhum comentário: