[Resolvido] Ajuda com outra session factory e injeção de dependencia em mesma aplicação

4 respostas
boneazul

Necessito em alguns pontos de um sistema utilizar outro banco de dados em paralelo ou seja outra session factory do hibernate que nao seja a padrao carregada pelo pacote vraptor-plugin-hibernate4-1.0.0.jar.

Em resumo meu banco padrao é um banco oracle e algumas telas tenho que acessar um banco de dados db2 , estou usando o hibernate 4.1.3, o guice como container de DI ,vraptor 3.4.1 , entao o que fiz foi o seguinte :

criei um hibernate.cfg.rdo.xml (nao padrao)

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		
		<property name="hibernate.dialect">org.hibernate.dialect.DB2Dialect</property>
		<property name="hibernate.connection.driver_class">com.ibm.db2.jcc.DB2Driver</property>
		<property name="hibernate.connection.url">jdbc:db2://localhost:50000/database</property>
		<property name="hibernate.connection.username">user</property>
		<property name="hibernate.connection.password">password</property>		
		
		 
		<property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
		<property name="hibernate.show_sql">true</property>
		<property name="hibernate.format_sql">true</property>
		<property name="hibernate.c3p0.min_size">1</property>
		<property name="hibernate.c3p0.max_size">20</property>
		<property name="hibernate.c3p0.timeout">30</property>
		<property name="hibernate.c3p0.idle_test_period">300</property>
		
		
        <mapping class="app.Regional" />

	</session-factory>
</hibernate-configuration>

a classe RdoSessionFactoryCreator :

@Component
@ApplicationScoped
public class RdoSessionFactoryCreator {

    private SessionFactory sessionFactory;
    private Configuration cfg;
    private ServiceRegistry serviceRegistry;

    public RdoSessionFactoryCreator() {
    	cfg = new Configuration().configure("hibernate.cfg.rdo.xml");
		ServiceRegistryBuilder builder = new ServiceRegistryBuilder();
		serviceRegistry = builder.applySettings(cfg.getProperties()).buildServiceRegistry();
    }

    @PostConstruct
    protected void create() {
        sessionFactory = cfg.buildSessionFactory(serviceRegistry);
    }

    @PreDestroy
    protected void destroy() {
        if (!sessionFactory.isClosed()) {
            sessionFactory.close();
        }
    }

    public SessionFactory getInstance() {
        return sessionFactory;
    }
}

e a classe RdoSessionCreator :

@Component
@RequestScoped
public class RdoSessionCreator {

    private Session session;
    private SessionFactory factory;
  
    //To achando meio gambiarra injetar RdoSessionFactoryCreator em vez de SessionFactory
    // e depois pegar com getInstance();
  public RdoSessionCreator(RdoSessionFactoryCreator factoryCreator) {
    	factory = factoryCreator.getInstance();
    }

    @PostConstruct
    public void create() {
        session = factory.openSession();
    }

    @PreDestroy
    public void destroy() {
        if (session.isOpen()) {
            session.close();
        }
    }

    public Session getInstance() {
        return session;
    }

}

e em um repositório chamo assim :

@Component
public class RegionalRepositoryImpl implements RegionalRepository {

	private Session session;
	
 //To achando meio gambiarra injetar RdoSessionCreator em vez de Session
    // e depois pegar com getInstance(); no mesmo caso acima
	public RegionalRepositoryImpl(RdoSessionCreator sessionCreator){
		this.session = sessionCreator.getInstance();
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Regional> listAll() {
		Criteria criteria = session.createCriteria(Regional.class);
		return criteria.list();
	}

}

Tem algum modo mais elegante de fazer isso injetando direto nos construtores os carinhas certos em vez de ter que ficar pedindo getInstance() toda vez ??

Nunca trabalhei com algo mais avançado de DI no vraptor , vi algumas coisas de fazer a classe implementar Provider e com @Named pegar direto no construtor direto , usando a especificação , mas num entendi direito o que preciso fazer pra funcionar , algum ai pode me ajudar a refatorar ?? Do jeito que está até funciona , mas sei la , meio estranho ficar injetando desse jeito.

Agradeço a ajuda

4 Respostas

Rafael_Guerreiro

Você está certo, dá para fazer de forma melhor mesmo e é com o provider do guice…
Primeiro você precisa criar um provider seu que vai “gerenciar” qual session e qual sessionFactory ele deve entregar…

public class CustomProvider extends GuiceProvider {

	static class CustomModule extends AbstractModule {
		private final Module module;

		CustomModule(Module module) {
			this.module = module;
		}

		@Override
		protected void configure() {
			install(this.module);
			bind(SessionFactory.class).toProvider(SessionFactoryProvider.class); // Meu SessionFactory padrão
			bind(SessionFactory.class)
					.annotatedWith(Names.named("SessionFactoryRDO")).toProvider(
							SessionFactoryRDOProvider.class); // Meu SessionFactoryRDO
			bind(Session.class).toProvider(SessionProvider.class); // Meu Session padrão
			bind(Session.class).annotatedWith(Names.named("SessionRDO"))
					.toProvider(SessionRDOProvider.class);// Meu SessionRDO
		}
	}

	@Override
	protected Module customModule() {
		return new CustomModule(super.customModule());
	}
}

Depois você registra esse provider lá no WEB.xml

&lt;context-param&gt;
		&lt;param-name&gt;br.com.caelum.vraptor.provider&lt;/param-name&gt;
		&lt;param-value&gt;pacote.do.custom.provider.CustomProvider&lt;/param-value&gt;
	&lt;/context-param&gt;

Ai no seu SessionFactoryRDOProvider deve ficar parecido com isso:

@ApplicationScoped
@javax.inject.Named("SessionFactoryRDO")
public class SessionFactoryRDOProvider implements
		Provider&lt;SessionFactory&gt; {

	private SessionFactory sessionFactory;

	@Inject
	public SessionFactoryRDOProvider () {
		// constroi sessionFactory e grava na variavel
	}

	@Override
	public SessionFactory get() {
		return sessionFactory;
	}

	@PreDestroy
	public void destroy() {
		sessionFactory.close(); // lembra de dar close
	}
}

A sua SessionRDO fica parecida (o nome tem que ser diferente…) mas com exceção de que no construtor, ela vai receber a SessionFactory que vem do RDO. Então o construtor fica assim:

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;

@Inject
	public SessionRDOProvider(
			@Named("SessionFactoryRDO") SessionFactory sessionFactory) {
		session = sessionFactory.openSession();
	}

Ai toda vez que você for usar a session RDO, voce recebe no construtor:

public class Classe {
   public Classe (@com.google.inject.name.Named("SessionRDO") Session session){
// usa a session...
}
}

Nessas classes que você registrou no CustomProvider, não precisa anotar com @Component… Mas deve anotar com @ApplicationScoped ou outro escopo…

boneazul

Hum maravilha cara vou refatorar aqui seguindo suas dicas . Muito obrigado pela ajuda !!!

boneazul

Funcionou que é uma beleza , vou postar a solução completa pra quem precisar desse tipo de coisa , creio que seria legal coloca no cookbook isso , ja que vejo muitas perguntas a respeito .

CustomProvider.java

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import br.com.caelum.vraptor.ioc.guice.GuiceProvider;

import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.name.Names;

public class CustomProvider extends GuiceProvider {

	static class CustomModule extends AbstractModule {
		private final Module module;

		CustomModule(Module module) {
			this.module = module;
		}

		@Override
		protected void configure() {
			install(this.module);
			bind(SessionFactory.class).annotatedWith(
					Names.named("SuaSessionFactoryCreator")).toProvider(
					RdoSessionFactoryCreator.class);
			bind(Session.class).annotatedWith(Names.named("SuaSessionCreator"))
					.toProvider(RdoSessionCreator.class);
		}
	}

	@Override
	protected Module customModule() {
		return new CustomModule(super.customModule());
	}
}

web.xml

<context-param>
		<param-name>br.com.caelum.vraptor.provider</param-name>
		<param-value>pacote.do.custom.provider.CustomProvider</param-value>
	</context-param>

SuaSessionFactoryCreator.java

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Named;
import javax.inject.Provider;
import javax.servlet.ServletContext;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

import br.com.caelum.vraptor.ioc.ApplicationScoped;


@ApplicationScoped
@Named("SuaSessionFactoryCreator")
public class SuaSessionFactoryCreator implements Provider<SessionFactory>{

    private SessionFactory sessionFactory;
    private Configuration cfg;
    private ServiceRegistry serviceRegistry;   

    public RdoSessionFactoryCreator() {
    	
	    	cfg = new Configuration().configure("seuhibernatecomomapeamentodooutrobanco.cfg.xml");
			ServiceRegistryBuilder builder = new ServiceRegistryBuilder();
			serviceRegistry = builder.applySettings(cfg.getProperties()).buildServiceRegistry();
    	
    }

    @PostConstruct
    protected void create() {
    	
    		sessionFactory = cfg.buildSessionFactory(serviceRegistry);
    	
    }

    @PreDestroy
    protected void destroy() {
    	
	    	if (!sessionFactory.isClosed()) {
	            sessionFactory.close();
	        }
    	
    	
    }

    public SessionFactory get() {
        return sessionFactory;
    }
}

SuaSessionCreator.java

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import br.com.caelum.vraptor.ioc.RequestScoped;


@RequestScoped
@Named("SuaSessionCreator")
public class SuaSessionCreator implements Provider<Session>{

    private Session session;
    private SessionFactory factory;

    @Inject
    public RdoSessionCreator(@Named("SuaSessionFactoryCreator") SessionFactory factory) {
    	this.factory = factory;
    }

    @PostConstruct
    public void create() {
        session = factory.openSession();
    }

    @PreDestroy
    public void destroy() {
        if (session.isOpen()) {
            session.close();
        }
    }

    public Session get() {
        return session;
    }

}

e por ultimo a injecao que voce precisar :
SeuRepositoryImplouDao .java

@Component
public class SeuRepositoryImplouDao {

	private Session session;
	
	public RegionalRepositoryImpl(@Named("SuaSessionCreator") Session session){
		this.session = session;
	}
}
Rafael_Guerreiro

Legal que funcionou! :smiley:

Edita lá o primeiro post e coloca o “[Resolvido]”…

Criado 23 de maio de 2012
Ultima resposta 24 de mai. de 2012
Respostas 4
Participantes 2