I have a problem trying to implement Multitenancy Hibernate in JPA application using Netbeans. The problem is that de method getEntityManager(String multitenancyIdentifier) is not executing the code inside itself, the value of parameter came null, so is not changing the schema.
In order to implement Multitenancy i had to include this 3 classes:
SchemaMultiTenantProvider.java
SchemaTenantResolver.java
MuiltitenancyResolver.java
You can find this example on this link: https://developers.redhat.com/blog/2020/11/12/jakarta-ee-multitenancy-with-jpa-on-wildfly-part-2#
In the SchemaMultiTenantProvider we have the line to change schema:
connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
In the SchemaTenantResolver we have a Map to select the schema in reference to user that will login to the app:
public SchemaTenantResolver(){
userDatasourceMap = new HashMap();
userDatasourceMap.put("default", "public");
userDatasourceMap.put("usuario1", "prueba");
}
And the MuiltitenancyResolver we set the tenantIdentifier, setted in getEntityManager(String multitenancyIdentifier):
public void setTenantIdentifier(String tenantIdentifier) {
this.tenantIdentifier = tenantIdentifier;
}
In the persistence i have this:
< provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
< jta-data-source>jdbc/dspw</jta-data-source>
< exclude-unlisted-classes>false</exclude-unlisted-classes>
< properties>
< property name="javax.persistence.schema-generation.database.action" value="none"/>
< property name="hibernate.dialect" value="org.hibernate.dialect.PostgresPlusDialect"/>
< property name="hibernate.multiTenancy" value="SCHEMA"/>
< property name="hibernate.tenant_identifier_resolver" value="services.SchemaTenantResolver"/>
< property name="hibernate.multi_tenant_connection_provider" value="services.SchemaMultiTenantProvider"/>
</ properties>
In my AbstractFacade i have this:
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
@PersistenceUnit
protected EntityManagerFactory emf;
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
public EntityManager getEntityManager(String multitenancyIdentifier){
System.out.println("id getEntityManager: " + multitenancyIdentifier);
final SessionFactoryImplementor sfi = emf.unwrap(SessionFactoryImplementor.class);
final MuiltitenancyResolver tenantResolver = (MuiltitenancyResolver) sfi.getCurrentTenantIdentifierResolver();
tenantResolver.setTenantIdentifier(multitenancyIdentifier);
return emf.createEntityManager();
}
In the same class i have this method to find any db object:
public T find(Object id, String multitenancyIdentifier) {
System.out.println("id find: " + multitenancyIdentifier);
return getEntityManager(multitenancyIdentifier).find(entityClass, id);
}
In one of Facades class (for the example) i have this:
public class UsuarioFacade extends AbstractFacade<Usuario> {
@PersistenceContext(unitName = "SPWPersistence")
private EntityManager em;
@Override
public EntityManager getEntityManager(String multitenancyIdentifier) {
System.out.println("User Facade: " + multitenancyIdentifier);
return em;
}
public UsuarioFacade() {
super(Usuario.class);
}
}
Finally i make a query using (userFacade) UsuarioFacade:
System.out.println("Test User: " + usuarioFacade.find(1,"usuario1").getNombre());
And this is the result:
id find: usuario1|#]
User Facade: usuario1|#]
Identificador schema: null|#]
Test User: Juan Perez Caceres|#]
The test User: Juan Perez Caceres is in the public schema (PostGres DB), but i am passing the user: usuario1 that correspont to schema: prueba (test). It is not changing the shema.
What can i do? O_o