Boa Tarde, estou com o seguinte problema, e não sei como resolver qual a melhor forma.
Preciso desenvolver um sistema WEB, que deve ser multiempresas. Terei apenas um sistema, mas que pode acessar bancos diferentes conforme a empresa informada.
Para isto utilizarei o Vraptor + PostGresql + Jquery ou Extjs.
Na tela de login, o usuário deve identificar sua empresa, o usuário e senha.
Para cada id de empresa, terei uma instancia do banco dados especifico. Todos no mesmo servidor.
Como posso fazer, para que o SessionFactory do Vraptor, saiba qual banco de dados ele precisa usar?
Tem como eu mudar o hibernate.cfg.xml, conforme for usar.
Espero ter sido claro na exposição do problema, e conto com a ajuda.
O que vc quer fazer se chama Multi Tenancy, e existe um jeito de fazer usando o Hibernate 4 nativamente.
Outra coisa que vc pode fazer é criar um componente application scoped que tenha as sessionFactories de todas as empresas, e um ComponentFactory que recebe o usuario logado e seleciona a sessionfactory apropriada para abrir a sessão.
[quote=Lucas Cavalcanti]O que vc quer fazer se chama Multi Tenancy, e existe um jeito de fazer usando o Hibernate 4 nativamente.
Outra coisa que vc pode fazer é criar um componente application scoped que tenha as sessionFactories de todas as empresas, e um ComponentFactory que recebe o usuario logado e seleciona a sessionfactory apropriada para abrir a sessão.[/quote]
Lucas, com base no que você falou, e pesquisando aqui mesmo no guj, cheguei a uma possível solução. seria corretep.
@ApplicationScoped
@Component
public class CriadorDeSessionFactory implements ComponentFactory<SessionFactory> {
private Map<Tenant, SessionFactory> conexoes = new HashMap<Tenant, SessionFactory>();
private Tenant tenant;
public CriadorDeSessionFactory(x) {
this.tenant = new Tenant();
}
public SessionFactory abre() {
SessionFactory factory;
Configuration configuration = new Configuration();
String arquivoConfiguracao = new StringBuilder().append(this.tenant).append(".cfg.xml").toString();
configuration.configure(arquivoConfiguracao);
factory = configuration.buildSessionFactory();
this.conexoes.put(this.tenant, factory);
return factory;
}
public SessionFactory getInstance() {
SessionFactory conexao = this.conexoes.get(tenant);
if (conexao == null) {
conexao = abre();
}
return conexao;
}
}
@RequestScoped
@Component
public class CriadorDeSession implements ComponentFactory<Session> {
private final SessionFactory factory;
private Session session;
public CriadorDeSession(SessionFactory factory) {
this.factory = factory;
}
@PostConstruct
public void abre() {
this.session = factory.openSession();
}
public Session getInstance() {
return this.session;
}
@PreDestroy
public void fecha() {
this.session.close();
}
}
@Component
public class Tenant {
private String tenantName;
public Tenant() {
this.tenantName = "demo";
}
public String getTenantName() {
return tenantName;
}
}
neste tenant, vou colocar a logica para buscar qual usar, a principio…o usuario ira passar no login. pensei em deixar isto numa classe de user, sessionscope.
dai deixo esta classe como aplicationscope, e trato no gettenantname?
na verdade eu trocaria o ComponentFactory por um componente normal chamado TenantSessionFactories, @applicationScoped que sabe retornar uma SessionFactory dado um Tenant
daí a ComponentFactory usa essa classe pra abrir a sesssion, dado um tenant.
[quote=Lucas Cavalcanti]vc precisa do tenant pra sessionFactory?
Ou só pra session?
na verdade eu trocaria o ComponentFactory por um componente normal chamado TenantSessionFactories, @applicationScoped que sabe retornar uma SessionFactory dado um Tenant
daí a ComponentFactory usa essa classe pra abrir a sesssion, dado um tenant.[/quote]
[quote=Lucas Cavalcanti]vc precisa do tenant pra sessionFactory?
Ou só pra session?
na verdade eu trocaria o ComponentFactory por um componente normal chamado TenantSessionFactories, @applicationScoped que sabe retornar uma SessionFactory dado um Tenant
daí a ComponentFactory usa essa classe pra abrir a sesssion, dado um tenant.[/quote].
Lucas, fiz umas alterações… mais ainda tenho uma duvida na minha classe Tenant. Onde esta usersLoggedIn = new UsersLoggedIn(), queria ver o usuario que esta na sessão. mas se colocar a criação desta classe no construtor da erro dizendo que sessionscope não pode ser usado no momento.
@Component
@SessionScoped
public class UsersLoggedIn {
private Users user;
private String empresa;
public String getEmpresa() {
return empresa;
}
public void setEmpresa(String empresa) {
this.empresa = empresa;
}
public boolean isLogged() {
return this.user != null;
}
public void setUser(Users user) {
this.user = user;
}
public Users getUser() {
return user;
}
}
@ApplicationScoped
@Component
public class Tenant {
private UsersLoggedIn usersLoggedIn;
public String getTenantName() {
usersLoggedIn = new UsersLoggedIn();
if (this.usersLoggedIn.getUser() == null) {
return new String("adm");
} else {
return this.usersLoggedIn.getEmpresa();
}
}
}
@RequestScoped
@Component
public class CriadorDeSession implements ComponentFactory<Session> {
private Session session;
private TenantSessionFactories tenantSessionFactories;
public CriadorDeSession(TenantSessionFactories tenantSessionFactories) {
this.tenantSessionFactories = tenantSessionFactories;
}
@PostConstruct
public void abre() {
this.session = this.tenantSessionFactories.abre();
}
public Session getInstance() {
return this.session;
}
@PreDestroy
public void fecha() {
this.session.close();
}
}
@ApplicationScoped
@Component
public class TenantSessionFactories {
private Map<String, SessionFactory> conexoes = new HashMap<String, SessionFactory>();
private Tenant tenant;
public TenantSessionFactories(Tenant tenant) {
this.tenant = tenant;
}
public Session abre() {
SessionFactory conexao = this.conexoes.get(tenant.getTenantName());
if (conexao == null) {
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
configuration.setProperty("hibernate.connection.url", "jdbc:postgresql://localhost:5432/"+this.tenant.getTenantName());
conexao = configuration.buildSessionFactory();
this.conexoes.put(this.tenant.getTenantName(), conexao);
}
return conexao.openSession();
}
}
Não queria pegar o tenant por base na url, por exemplo: minhaempresa.app.com.br… pois um mesmo usuario podera acessar mais de 1 empresa. dai queria que ele escolhesse no login