Dúvida Mentawai + Hibernate + DAO Genérico + TransactionFilter = RESOLVIDO

Pessoal é o seguinte:

Estou usando o framework Mentawai 1.8 e Hibernate 3.2 + annotations;

Ai ocorre o seguinte eu tenho classes DAO que, ao serem instânciadas, usam o seguinte factory:

public class HibernateDAOFactory extends DAOFactory {

	public HibernateDAOFactory() {}

	public UsuarioDAO getUsuarioDAO() {
		return (UsuarioDAO) instanciarDAO(HibUsuarioDAO.class);
	}
	
	private HibGenericDAO instanciarDAO(Class daoClass) {
        try {
        	HibGenericDAO dao = (HibGenericDAO)daoClass.newInstance();
            dao.setSession(getCurrentSession());
            return dao;
        } catch (Exception ex) {
            throw new RuntimeException("Não foi possível instanciar o DAOFactory: " + daoClass, ex);
        }
    }
	
    protected Session getCurrentSession() {
    	try{
    		return HibernateUtil.getSessionFactory().getCurrentSession();
    	}catch (HibernateException ex ){
    		return HibernateUtil.getSessionFactory().openSession();
    	}
    }
}

Como foi possível perceber, a session é atribuida durante o instanciar da classe.

Primeira pergunta: Alguém tem alguma sugestão para melhorar este processo uma vez que eu não tenho como fechar a Session aberta?

Só que, como o Mentawai tem uma funcionalidade para gerenciamento de sessões hibernate, configurei, debuguei e percebi que este funcionando corretamente, gostaria de usar esta funcionalidade mas não vejo onde usar. E ainda por cima debuguei e precebi que sempre é gerada uma exceção quando utilizo getCurrentSession, o que ocasiona em uma nova abertura de Session.

nota: A instância de SessionFactory utilizada pelo framework é a mesma utilizada pela classe acima.

Segunda pergunta: O que fazer uma vez que a interface de um DAO não deve conhecer, por exemplo, um método setSession?

Só pra terminar, quando utilizo o TransactionFilter do mentawai, desta forma (Em ApplicationManager)

@Override
	public void init(Context application) {

		ioc("transaction", HibernateTransaction.class);

	}

	public void loadActions() {

		// -------------IoC Global Filter-----------------
		filter(new IoCFilter());
		// -----------------------------------------------

		// -------------Hibernate Filter------------------
		addGlobalFilter(new HibernateFilter(HibernateUtil.getSessionFactory()));
		// -----------------------------------------------

		ActionConfig ac = null;

		// --------------INICIAR ACTION-------------------
		ac = new ActionConfig("/iniciar", Iniciar.class).addConsequence(
				SUCCESS, new Forward(PREFIXO_VIEW + "/iniciar.jsp"))
				.addConsequence(ERROR, new Forward(PAGINA_DE_ERRO_JSP));
		addActionConfig(ac);
		// -----------------------------------------------

		// make this action atomic !!!!
		// by default this filter will look for a transaction with the name
		// "transaction" in the action input
		// refer above that this is exactly like we defined our IoC component...
		ac.addFilter(new TransactionFilter());

	}

Tenho a seguinte pilha de erros:

exception

javax.servlet.ServletException: Exception while invoking action iniciar: null
	org.mentawai.core.Controller.service(Controller.java:537)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

root cause

java.lang.NullPointerException
	org.mentawai.transaction.HibernateTransaction.rollback(HibernateTransaction.java:91)
	org.mentawai.filter.TransactionFilter.filter(TransactionFilter.java:136)
	org.mentawai.core.InvocationChain.invoke(InvocationChain.java:91)
	org.mentawai.filter.HibernateFilter.filter(HibernateFilter.java:186)
	org.mentawai.core.InvocationChain.invoke(InvocationChain.java:91)
	org.mentawai.filter.DIFilter.filter(DIFilter.java:171)
	org.mentawai.core.InvocationChain.invoke(InvocationChain.java:91)
	org.mentawai.filter.IoCFilter.filter(IoCFilter.java:82)
	org.mentawai.core.InvocationChain.invoke(InvocationChain.java:91)
	org.mentawai.core.Controller.invokeAction(Controller.java:635)
	org.mentawai.core.Controller.service(Controller.java:496)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

Por favor HELP!!!

Algumas perguntas e dicas pra você:

  • Porque você criou uma factory de DAOs?
  • Porque você criou interfaces pra eles?
  • Porque você não usa simplesmente o pattern OpenSessionInView?
  • Seu método getCurrentSession() teoricamente não lançaria exception no openSession() à toa. Qual o problema?

Ae povo, foi dificil mas consegui… finalmente!!!

Bom para curiosos de plantão segue a solução:

A classe HibernateDAOFactory:

public class HibernateDAOFactory extends DAOFactory {

	private Session session = null;
	
	public HibernateDAOFactory() {}

	public UsuarioDAO getUsuarioDAO() {
		return (UsuarioDAO) instanciarDAO(HibUsuarioDAO.class);
	}
	
	private HibGenericDAO instanciarDAO(Class daoClass) {
        try {
        	HibGenericDAO dao = (HibGenericDAO)daoClass.newInstance();
        	dao.setSession(session);
            return dao;
        } catch (Exception ex) {
            throw new RuntimeException("Não foi possível instanciar o DAOFactory: " + daoClass, ex);
        }
    }
    
    public Session getSession() {
		return session;
	}

	public void setSession(Session session) {
		this.session = session;
	}
	
}

Na ApplicationManager:

public void init(Context application) {
		ioc("transaction", HibernateTransaction.class, REQUEST);
		ioc(HibernateFilter.KEY, Session.class, REQUEST);
		ioc("factory", HibernateDAOFactory.class, REQUEST);
	}

	public void loadActions() {

		// o filtro global que transforma o Mentawai num container de IoC
		// -------------IoC Global Filter-----------------
		filter(new IoCFilter());
		// ----------------------------------------------

		// Injection filter to inject values straight into the action
		filter(new InjectionFilter());

		// -------------Hibernate Filter------------------
		addGlobalFilter(new HibernateFilter(HibernateUtil.getSessionFactory()));
		// -----------------------------------------------

		filter(new DIFilter(HibernateFilter.KEY, "session", Session.class));

		filter(new DIFilter("factory", HibernateDAOFactory.class));

		ActionConfig ac = null;

		// --------------INICIAR ACTION-------------------
		ac = new ActionConfig("/iniciar", Iniciar.class).addConsequence(
				SUCCESS, new Forward(PREFIXO_VIEW + "/iniciar.jsp"))
				.addConsequence(ERROR, new Forward(PAGINA_DE_ERRO_JSP));
		addActionConfig(ac);
		// -----------------------------------------------

		ac.addFilter(new TransactionFilter());
	}

E em qualquer action que eu precisar, basta declarar o HibenateDAOFactory ou até mesmo a interface DAOFactory como um atributo.

Dai é só usar, dentro do execute por exemplo, os métodos do DAOFactory e ir para o abraço!!!

Você ao menos leu o que escrevi ali em cima?

Li sim.

E concordo com seus questionamentos quando temos um projeto que é desenvolvido só por uma pessoa, por que complicar se podemos facilitar não é!?!?. Porém, este não é o caso.

Minha responsabilidade é toda a parte de análise e também desenvolvimento da arquitetura do sistem. Então acredito que, com esta solução que alcancei, fica muito mais fácil o trabalho dos outros dois profissionais que vão trabalhar comigo. Uma vez que nenhum deles conhece hibernate, fica transparente para eles todo o controle de sessões e transações. Só vão se preocupar com a validação dos dados, regra de negócio e de persistir os dados através dos DAO´s.

Concorda ou discorda?!?!?Penso desta forma mas é a primeira vez que trabalho em um projeto com uma equipe.

Abraço,

cesarcneto,

Meus questionamentos tem o propósito justamente de ajudar você e tornar mais simples o desenvolvimento pra você e sua equipe. Se você está trabalhando com Hibernate, acredite, as chances de você trocar de framework de ORM são praticamente, nulas. E isso já tira muito do mérito de você usar as interfaces pra DAOs (e também pra DAOFactory).

E isso nos leva à outro ponto, porque você criou uma DAOFactory? Você saberia explicar porque que o pattern factory se encaixa no seu problema? Melhorando a pergunta inclusive, existe um problema a ser resolvido aqui?

[]

plentz.

Concordo com grande parte do que você falou. Na verdade estava usando esse tipo de arquitetura porque a utilizei em outros sistemas que desenvolvi. A diferença é que todos os outros utilizavam JDBC puro e, por haver a necessidade de futuramente a forma de perisistência ser alterada, acredito que era uma boa solução.

Agora estudando o hibernate e desenvolvendo um projeto utilizando ele estou começando a parceber que realmente não há muita necessidade de se preocupar com uma arquitetura complexa e flexível…

Acho que vou acabar modificando minha arquitetura para usar apenas DAO´s já que isolando a persistência posso criar os logs necesários para depuração de erros e talz…

Sobre suas perguntas, desculpe mas tecnicamente ainda não comecei estudar patterns… Então não sei ao certo explicar por cada um deles. Infelizmente ainda sou muito novato em desenvolvimento e pricipalmente em Java onde atuo à apenas um ano dos um ano e meio que trabalho com desenvolvimento…

Então é isso ai…
Abraço,