quinta-feira, 30 de agosto de 2007

Fábrica de DAOs com Reflection

Olá a todos,
Sabemos que uma boa prática na modelagem de arquiteturas de software é a serapação das responsabilidades em camadas bem definidas. Uma destas camadas, talvez a que esteja mais relacionada com os recursos da infra-estrutura, é a de Persistencia dos dados. Para esta camada, é comum utilizar-se o pattern Data Access Object (DAO), que tem o objetivo de encapsular estes acessos aos recursos de armazenamento de dados (normalmente bancos de dados relacionais).
Além da separação de camadas, ouve-se muito falar que é importante manter um fraco acoplamento entre elas, tornando assim, mais independentes para futuras manutenções. Mas como garantir este fraco acoplamento? Segue um exemplo de utilização de uma DAO na camada de negócios:

ClienteDao dao = new ClienteDao(HibernateUtil.getSession());
dao.adiciona(cliente);

Implementando desta forma, caso seja necessário refatorar a classe de acesso a dados de Clientes, ou mesmo criar uma nova versão desta classe que não utilizasse hibernate, mas sim acesso direto via JDBC, o que teria que ser feito? Teríamos que criar uma nova classe, por exemplo: ClienteDaoJDBC e implementar todos os metodos novamente. Até aí tudo bem, nada problemático. Mas o problema está na utilização da classe, imagine que quem for cliente da classe ClienteDao terá que mudar o tipo da variável/atriuto para ClienteDaoJDBC. Aí que está o Alto acoplamento.
Para resolver isso é interessante criar interfaces para as DAOs, e então as classes ClienteDao e ClienteDaoJDBC implementariam estas interfaces. Quem fosse utilizar as DAOs usariam variável/atributo do tipo da interface: IFClienteDao por exemplo. Com isso já resolvemos o problema de ter que alterar o tipo da variável/atributo, mas ainda temos o alto acoplamento representado pela instrução new, conforme o código abaixo:

IFClienteDao dao = new ClienteDaoJDBC();

Para resolvermos o problema do alto acoplamento, devemos então criar uma Fábrica de Daos. Uma classe que fosse responsável por instanciar nossas DAOs e tirar esta responsabilidade do cliente das classes DAOs, assim o dia que for necessário alterar a DAO a ser usada, seria só alterar nesta Fábrica. Este conceito de Fábrica segue o pattern Factory definido pelo GoF.
Uma fábrica de Daos poderia ser uma singleton, pois não parece ser necessário ter mais de uma instancia desta classe, então o código ficaria:

public class DaoFactory {
// controle da singleton
private static DaoFactory factory = new DaoFactory();

// construtor private para não permitir instanciar a factory diretamente com new.
private DaoFactory() {}

// através deste método é que se obtem a fábrica.
// excepcionalmente este método recebe um atributo session pois este pode mudar
// durante o tempo de vida da aplicação se assim o hibernate desejar :D
public static DaoFactory getInstance(Session session) {
factory.setSession(session);
return factory;
}

public IFClienteDao getClienteDao() {
return new ClienteDaoJDBC();
}
}


Com esta fábrica é possível obter DAOs sem saber o que é preciso disponibilizar à ela, mais uma vez o papel de encapsulamento ajudando.
Mas ainda tem-se um pequeno problema, conforme o sistema for crescendo, muitas daos são criadas e muitos getXXXDao() vão sendo adicionados à fabrica. Quando ocorre estes métodos repetitivos, já é possível imaginar que poderia-se criar um getDao genérico que retornasse a Dao respectiva de uma classe persistente, por exemplo: "Quero que retorne a DAO referente a persistencia dos dados da classe Cliente", então a fábrica retornaria a ClienteDaoJDBC por exemplo. Para isso pode ser utilizado Java Reflection conforme o código a seguir:

private static DaoFactory factory = new DaoFactory();
private Session session;
private Map daoMap = new HashMap();

public Dao getDao(Class persistentClass) {
if (daoMap.containsKey(persistentClass)) {
return daoMap.get(persistentClass);
}
else {
if (persistentClass.isAnnotationPresent(DaoClass.class)) {
DaoClass daoClassInfo = (DaoClass)persistentClass.getAnnotation(DaoClass.class);
Dao dao = null;
try {
dao = daoClassInfo.value().getConstructor(Session.class, Class.class).newInstance(this.session, persistentClass);

if (daoClassInfo.singleton()) {
daoMap.put(persistentClass, dao);
}

return dao;
}
catch (Exception e) {
throw new DaoFactoryException("A classe Dao não pode ser instanciada. Erro: " + e.getMessage());
}
}
else {
throw new DaoFactoryException("Anotação @DaoClass ausente");
}
}
}
Não adicionei comentários neste código pois está bem legível. Espero que tenha sido útil.

[]'s

terça-feira, 21 de agosto de 2007

JBoss Rules (Drools)

Olá a todos,

Hoje estarei publicando apenas links de documentos que possuo aqui em casa sobre um framework da JBoss estou estudando atualmente, chamado JBoss Rules. Não vou me estender muito com explicações, pois ainda não tenho muitas certezas em relação à utilização deste framework. Mesmo sem essas certezas, continuo apostando que este JBoss Rules irá trazer muitos benefícios aos meus projetos, que buscam uma arquitetura orientada a serviços (SOA) e regras de negócios que podem mudar frequentemente. Também estou achando interessante a integração deste framework com o JBPM, que é um framework para trabalhar com Business Process Management em Java (WorkFlows avançados).

Em poucas palavras, o JBoss Rules é um framework Open Source para "externalizar" regras de negócio e/ou lógicas corporativas a fim de tornar o processo de manutenção e novas implementações mais rápido e seguro. Com essas regras externas, que podem ser escritas até em uma linguagem natural, qualquer stakeholder pode ler e interpretar, podendo assim garantir que elas realmente façam o que deveriam fazer.

Seguem os links:
- http://www.inf.furb.br/~gfronza/JBoss_Rules.pdf
- http://www.inf.furb.br/~gfronza/Apresentacao_JBoss_Rules.pdf


Mais informações sobre o framework podem ser encontrados no site da JBoss

Se tiverem interesse sobre o assunto podemos trocar ideias por e-mail ou IM.
[]'s

terça-feira, 14 de agosto de 2007

"AutoRelacionamento" com Hibernate

Hoje tive que implementar o menu de uma aplicação que estou fazendo e precisava de uma classe que representasse uma tabela mais ou menos assim:

CREATE TABLE sis_menu (
id bigint(20) NOT NULL,
acao varchar(255) default NULL,
chave varchar(255) NOT NULL,
idMenuPai bigint(20) default NULL,
PRIMARY KEY (`id`),
KEY `fk_id_pai` (`idMenuPai`),
FOREIGN KEY (`idMenuPai`) REFERENCES `sis_menu` (`id`)
)

Ou seja, tinha que fazer um relacionamento da tabela sis_menu com ela mesma para ter uma hierarquia dos itens do menu.

Para isso escrevi a seguinte classe POJO com anotações do hibernate:

@Entity
@Table(name="sis_menu")
public class Menu {

@Id @GeneratedValue
private Long id;

@NotEmpty(message="menu.chaveEmpty")
private String chave;

private String acao;

@OneToMany(mappedBy="menuPai", fetch=FetchType.LAZY)
@Cascade(CascadeType.ALL)
private List\ subMenus;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="idMenuPai", insertable=true, updatable=true)
@Fetch(FetchMode.JOIN)
@Cascade(CascadeType.SAVE_UPDATE)
private Menu menuPai;

// getters e setters
}

Não cheguei nesta solução sozinho, o que fiz foi googlear até achar isso. Acabei encontrando um PDF em portugues muito bom que ensina como utilizar mapeamentos no hibernate. Segue o link:
ftp://users.dca.ufrn.br/hibernate_anotacoes/T03_Relacionamentos_1.pdf

segunda-feira, 13 de agosto de 2007

Alterando variável java.library.path em tempo de execução

Olá a todos,

Estou postando aqui um trecho de código que eu e dois colegas (Israel e Gustavo) encontramos para solucionar um problema bem simples. Estavamos desenvolvendo uma ferramenta que utilizava o framework JOGL, e além do jogl.jar tinhamos que carregar uma dll também do jogl. Para carregar esta dll tinhamos então que colocar elas, ou no path do sistema operacional (nem um pouco indicado pois no nosso caso nem teriamos como gravar arquivos nos diretórios do C:/... por motivos de falta de permissão) apontada pela variável java.library.path, ou colocar na raiz da aplicação. Mas queríamos que as dlls ficassem dentro da pasta lib do nosso projeto. Para resolver isso procuramos na web uma forma de alterar a variável java.library.path somente em tempo de execução e ao finalizar o aplicativo esta variável seria reinicializada com o valor anterior.

A idéia é simples e o código também:

try {
Class clazz = ClassLoader.class;
Field field = clazz.getDeclaredField("sys_paths");

boolean accessible = field.isAccessible();
if (!accessible)
field.setAccessible(true);
Object original = field.get(clazz);

field.set(clazz, null);
try {
System.setProperty("java.library.path", System.getProperty("java.library.path") + ";" + new File("").getAbsolutePath() + File.separator + "lib");
System.loadLibrary("jogl");
}
finally {
field.set(clazz, original);
field.setAccessible(accessible);
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}

Prometo que os próximos códigos irei postar em um Pastbin, mas ainda não achei nenhum decente...

[]'s

domingo, 12 de agosto de 2007

Motivo da criação deste Blog...

Decidi criar este blog, inicialmente para ter um local na rede onde eu pudesse expor algumas idéias, problemas já passados para resolver determinados problemas, utilização com ou sem sucesso de algumas tecnologias, enfim, tudo que possa ajudar outras pessoas a tomarem decisões sobre a escolha de tecnologias na área de TI.

Tentarei escrever sobre algumas experiências que já tive na área de computação. Atualmente sou desenvolvedor Java EE e SE, mas utilizo também outras tecnologias como: Lua, OpenLaszlo, etc.

Gosto muito de trocar idéias sobre como modelar arquiteturas de software, estudar metodologias de desenvolvimento ágil, como XP, Scrum, e o recente (pelo menos para mim) OpenUp da IBM juntamente com o Eclipse. Gosto também de conhecer novos frameworks que proporcionam produtividade e sobretudo qualidade.

Sobre Java Web atualmente utilizo as tecnologias:
- VRaptor - Controlador MVC
- Hibernate - JPA
- JSP + EL + Taglibs
- JBoss + Tomcat - Servidor de Aplicações + Servelt Container

Também estou estudando, e documentando bem, como criar plugins para o Eclipse. Sobre isso quero focar, principalmente, na parte da criação de editores (com syntax check e syntax highlight), pois o resto é trivial e já possuem diversas documentações que podem ser encontradas no google ;).

É isso... abraços