Solved. My step by step solution:
1. persistence.xml: into persistence-unit "myPersistenceUnit"
Code:
<property name="hibernate.multiTenancy" value="SCHEMA"/>
<property name="hibernate.multi_tenant_connection_provider" value="util.MultiTenantConnectionProviderImpl"/>
<property name="hibernate.tenant_identifier_resolver" value="util.MultiTenantIdentifierResolverImpl"/>
2. ConnectionProviderImpl
Code:
public class ConnectionProviderImpl implements ConnectionProvider {
@Override
public Connection getConnection() throws SQLException {
String jndiName = "myPersistenceUnit";
DataSource ds = null;
try {
InitialContext ic = new InitialContext();
ds = (DataSource) ic.lookup(jndiName);
return ds.getConnection();
} catch (NamingException e) {
return null;
}
}
@Override
public void closeConnection(Connection conn) throws SQLException {
conn.close();
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(Class type) {
return false;
}
@Override
public <T> T unwrap(Class<T> type) {
return null;
}
}
3. MultiTenantConnectionProviderImpl
Code:
public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider, Stoppable {
private final ConnectionProvider connectionProvider = new ConnectionProviderImpl();
@Override
public void stop() {
}
@Override
public Connection getAnyConnection() throws SQLException {
return connectionProvider.getConnection();
}
@Override
public void releaseAnyConnection(Connection conn) throws SQLException {
connectionProvider.closeConnection(conn);
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection conn = getAnyConnection();
setSchema(tenantIdentifier, conn);
return conn;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection conn) throws SQLException {
setSchema("public", conn);
releaseAnyConnection(conn);
}
private void setSchema(String tenantIdentifier, Connection conn) {
try {
conn.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
} catch (SQLException e) {
throw new HibernateException("MultiTenantConnectionProviderImpl::Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]",e);
}
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(Class type) {
return false;
}
@Override
public <T> T unwrap(Class<T> type) {
return null;
}
}
4. MultiTenantIdentifierResolverImpl
Code:
public class MultiTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
public static ThreadLocal<String> tenantIdentifier = new ThreadLocal<>();
@Override
public String resolveCurrentTenantIdentifier() {
String currentTenantIdentifier = tenantIdentifier.get();
if (currentTenantIdentifier == null)
currentTenantIdentifier = "public";
return currentTenantIdentifier;
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}
5. Filter to set up the actual tenantIdentifier
Code:
public class OpenSessionInViewFilter implements Filter {
...
@Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
throws IOException, ServletException {
...
HttpSession session = ((HttpServletRequest)req).getSession(false);
if (session != null) {
String currentTenant = (String) session.getAttribute("currentTenant");
if (!Geral.StrEmpty(currentTenant))
MultiTenantIdentifierResolverImpl.tenantIdentifier.set(currentTenant);
}
...
}
}