22 de mai. de 2009

RMI e HIbernate... lições aprendidas


Estou participando de um projeto onde decidimos utilizar RMI para conversação de dois módulos do sistema. A decisão não vem ao caso agora, mas achei interessante gurdas alguns "causos"...


RMI e Hibernate, onde tudo começou


Como falei anteriormente, decidimos utilizar RMI para integrar dois módulos do sistema. Um módulo responsável pela parte de negócio( persistência também) e outro por uma parte específica bem baixo nível (baixo nível = bytes.. 01010101...etc...).

Então, o gênio projetista teve a seguinte idéia: "Vamos utilizar as classes persistentes para trafegar via RMI".

Resultado: LazyInitializationException -LIE.


Em um determinado método de uma classe acessada via RMI o retorno era um objeto que foi buscado do Hibernate. Este objeto tinha outros objetos, que tinham outros objetos, que tinham outros objetos... blá blá blá...

Soluções:


1º) Colocar "transient"(do java não do JPA) nos atributos que não deveriam trafegar via RMI. Puramor de Deus, Nãããão!!!

Imagina ficar colocando transiente em tudo que é atributo espalhado pelo código inteiro. Loucura!!!

2º) Modificar o design
Interessante... muito interessante...
O Design... (não é de moda porr!!)


Tentei fazer algo que representasse o problema. Então abaixo estão algumas classes de domínio, mapeadas no hibernate.


OBS: Para quem não sabe, em RMI devem existir interfaces comuns nos dois lados da comunicação. Então a interface PessoaData é conhecida pelos dois módulos.


Agora, viram o que o projetista gênio fez ?!?!?!

A classe Pessoa implementa a interface PessoaData. Na imagem acima temos somente um exemplo, mas no contexto real são umas 20 classes que irão trafegar via RMI. Todas essas classes são entidades persistentes.

Observe que a interface PessoaData retorna byte[]. Isso mesmo.. o "carinha" que utiliza estas classes vai precisar dos dados convertidos em bytes. Guarde esta informação.


Confesso que o projetista gênio(agora já deve-se saber quem é o projetista... :D ) percebeu a burrada somente quando ocorreu o erro com hibernate.


O que vocês conseguem enchergar ai?

Bom, vou dizer o que eu consegui enxergar:

  • Uma classe persistente implementa uma interface utilizada para comunicação entre sistemas. Acomplamento! Entidade persistente conhece uma interface onde o objetivo é comunicação de dados entre sistemas... "nada a vê"
  • Pelo motivo acima, a entidade persistente é responsável por converter String, Integer, Date em bytes. Coesão! Tava tudo misturado, conversões com bytes em uma classe onde o objeto é enviar e obter informações do banco de dados.

Solução tomada

Utilizamos os famosos Transfer Objects. Segue o exemplo:




Matamos o problema de coesão, onde a classe PessoaTo é responsável por trabalhar os dados para comunicação.
Matamos o problema de acomplamento onde a classe Pessoa não sabe que a classe PessoaTo existe.
Matamos o LazyInitializationException. A classe TO contém apenas o que será necessário para transferência.

Lições aprendidas
  • Colocar tudo em uma classe é diferente de economizar tempo
  • Preguisoço trabalha em dobro... :D
  • Projetos iterativos minimizam os erros. Descobrimos o problema no início e retrabalho foi de aproximadamente 5hs.
  • Enviar objetos utilizados para persistência via RMI-> ... LazyInitializationException
  • Spring RMI exporter facilita muito!
  • Cuidar as dependências das classes

Era isso..

Abraço!