Hi guys. I’m new here. I’m trying to implement muti-tenancy using Hibernate, but when I deploy the app to Payara server, an exception occured: java.lang.ClassCastException: com.sun.enterprise.container.common.impl.EntityManagerFactoryWrapper cannot be cast to org.hibernate.engine.spi.SessionFactoryImplementor
Below is my code.
DatabaseMultiTenantProvider.java
public class DatabaseMultiTenantProvider implements MultiTenantConnectionProvider, ServiceRegistryAwareService {
private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseMultiTenantProvider.class);
private static final long serialVersionUID = 1L;
private static final String TENANT_SUPPORTED = "DATABASE";
private DataSource dataSource;
private String typeTenancy;
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
typeTenancy = (String) ((ConfigurationService) serviceRegistry
.getService(ConfigurationService.class))
.getSettings().get("hibernate.multiTenancy");
dataSource = (DataSource) ((ConfigurationService) serviceRegistry
.getService(ConfigurationService.class))
.getSettings().get("hibernate.connection.datasource");
}
@SuppressWarnings("rawtypes")
@Override
public boolean isUnwrappableAs(Class clazz) {
return false;
}
@Override
public <T> T unwrap(Class<T> clazz) {
return null;
}
@Override
public Connection getAnyConnection() throws SQLException {
final Connection connection = dataSource.getConnection();
return connection;
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
//Just use the multitenancy if the hibernate.multiTenancy == DATABASE
if (TENANT_SUPPORTED.equals(typeTenancy)) {
try {
Properties props = FileIO.loadProperties(DatabaseMultiTenantProvider.class.getClassLoader().getResource("config/dbconfig.properties").getFile());
String host = props.getProperty("hq.host");
String port = props.getProperty("hq.port");
String user = props.getProperty("hq.user");
String password = props.getProperty("hq.password");
MysqlDataSource mysqlDataSource = new MysqlDataSource();
String DB_URL = "jdbc:mysql://" + host + ":" + port + "/" + tenantIdentifier + "?serverTimezone=UTC&user=" + user + "&password=" + password;
mysqlDataSource.setURL(DB_URL);
dataSource = mysqlDataSource;
} catch (IOException ex) {
LOGGER.error("Could not load database configuration file. {}", ex);
}
}
return dataSource.getConnection();
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
connection.close();
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
releaseAnyConnection(connection);
}
}
DatabaseTenantResolver.java
public class DatabaseTenantResolver extends MultitenancyResolver {
private final Map<String, String> userDatasourceMap;
public DatabaseTenantResolver() {
userDatasourceMap = new HashMap();
userDatasourceMap.put("default", "ibigtime");
userDatasourceMap.put("bigtime", "bigtime");
}
@Override
public String resolveCurrentTenantIdentifier() {
if (this.tenantIdentifier != null && userDatasourceMap.containsKey(this.tenantIdentifier)) {
return userDatasourceMap.get(this.tenantIdentifier);
}
return userDatasourceMap.get("default");
}
@Override
public boolean validateExistingCurrentSessions() {
return false;
}
}
MultitenancyResolver.java
public abstract class MultitenancyResolver implements CurrentTenantIdentifierResolver {
protected String tenantIdentifier;
public void setTenantIdentifier(String tenantIdentifier) {
this.tenantIdentifier = tenantIdentifier;
}
}
Dao.java
public abstract class Dao<T extends Entity> {
@PersistenceUnit
private EntityManagerFactory emf;
protected EntityManager getEntityManager(String multitenancyIdentifier) {
final MultitenancyResolver tenantResolver = (MultitenancyResolver) ((SessionFactoryImplementor) emf).getCurrentTenantIdentifierResolver();
tenantResolver.setTenantIdentifier(multitenancyIdentifier);
return emf.createEntityManager();
}
public Optional<T> findById(T entity, String multitenancyIdentifier) {
return (Optional<T>) Optional
.ofNullable(getEntityManager(multitenancyIdentifier).find(entity.getClass(), entity.getId()));
}
public T save(T entity, String multitenancyIdentifier) {
getEntityManager(multitenancyIdentifier).persist(entity);
return entity;
}
public T update(T entity, String multitenancyIdentifier) {
getEntityManager(multitenancyIdentifier).merge(entity);
return entity;
}
public void remove(T entity, String multitenancyIdentifier) {
getEntityManager(multitenancyIdentifier).remove(entity);
}
}
The exception is occured when we cast EntityManagerFactory to SessionFactoryImplementor in the method getEntityManager() of the Dao.java file.
I follow the code from the article: https://developers.redhat.com/blog/2020/06/15/jakarta-ee-multitenancy-with-jpa-on-wildfly-part-1# but It doesn’t work on Payara Server. Could anyone tell me how to work around this problem? Thanks