BAEL-399: A Guide to Multitenancy in Hibernate 5 (#3235)

* BAEL-399: A Guide to Multitenancy in Hibernate 5

* Removed unused properties in profile 2
This commit is contained in:
Jose Carvajal
2017-12-24 00:23:21 +01:00
committed by KevinGilmore
parent 13d47f0873
commit 85f12cd254
21 changed files with 302 additions and 385 deletions

View File

@@ -1,30 +0,0 @@
package com.baeldung.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.baeldung.hibernate.pojo.Supplier;
/**
* Hello world!
*
*/
public class App {
public static void main(String[] args) {
try {
// NOTE: this is just for boostrap testing for multitenancy.
System.out.println("Checking the system.");
SessionFactory sessionFactory = HibernateMultiTenantUtil.getSessionFactory();
Session currentSession = sessionFactory.withOptions().tenantIdentifier("h2db1").openSession();
Transaction transaction = currentSession.getTransaction();
transaction.begin();
currentSession.createCriteria(Supplier.class).list().stream().forEach(System.out::println);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,41 +0,0 @@
package com.baeldung.hibernate;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
public class ConfigurableMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
private final Map<String, ConnectionProvider> connectionProviderMap =
new HashMap<>();
public ConfigurableMultiTenantConnectionProvider(
Map<String, ConnectionProvider> connectionProviderMap) {
this.connectionProviderMap.putAll( connectionProviderMap );
}
@Override
protected ConnectionProvider getAnyConnectionProvider() {
System.out.println("Any");
return connectionProviderMap.values().iterator().next();
}
@Override
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
System.out.println("Specific");
return connectionProviderMap.get( tenantIdentifier );
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
Connection connection = super.getConnection(tenantIdentifier);
// uncomment to see option 2 for SCHEMA strategy.
//connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
return connection;
}
}

View File

@@ -1,115 +0,0 @@
package com.baeldung.hibernate;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.ServiceRegistry;
import com.baeldung.hibernate.pojo.Supplier;
public class HibernateMultiTenantUtil {
private static SessionFactory sessionFactory;
private static Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
private static final String[] tenantDBNames = { "mydb1", "mydb2" };
public static SessionFactory getSessionFactory() throws UnsupportedTenancyException, IOException {
if (sessionFactory == null) {
// Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = configureServiceRegistry();
sessionFactory = makeSessionFactory(serviceRegistry);
}
return sessionFactory;
}
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
for (Class annotatedClasses : getAnnotatedClasses()) {
metadataSources.addAnnotatedClass(annotatedClasses);
}
Metadata metadata = metadataSources.buildMetadata();
return metadata.getSessionFactoryBuilder()
.build();
}
private static Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Supplier.class };
}
private static ServiceRegistry configureServiceRegistry() throws UnsupportedTenancyException, IOException {
// Properties properties = configuration.getProperties();
Properties properties = getProperties();
connectionProviderMap = setUpConnectionProviders(properties, tenantDBNames);
properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, new ConfigurableMultiTenantConnectionProvider(connectionProviderMap));
return new StandardServiceRegistryBuilder().applySettings(properties)
.build();
}
private static Properties getProperties() throws IOException {
Properties properties = new Properties();
URL propertiesURL = Thread.currentThread()
.getContextClassLoader()
.getResource("hibernate-multitenancy.properties");
FileInputStream inputStream = new FileInputStream(propertiesURL.getFile());
properties.load(inputStream);
System.out.println("LOADED PROPERTIES FROM hibernate.properties");
return properties;
}
private static Map<String, ConnectionProvider> setUpConnectionProviders(Properties properties, String[] tenantNames) throws UnsupportedTenancyException {
Map<String, ConnectionProvider> providerMap = new HashMap<>();
for (String tenant : tenantNames) {
DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
String tenantStrategy = properties.getProperty("hibernate.multiTenancy");
System.out.println("Strategy:" + tenantStrategy);
properties.put(Environment.URL, tenantUrl(properties.getProperty(Environment.URL), tenant, tenantStrategy));
System.out.println("URL:" + properties.getProperty(Environment.URL));
connectionProvider.configure(properties);
System.out.println("Tenant:" + tenant);
providerMap.put(tenant, connectionProvider);
}
System.out.println("Added connections for:");
providerMap.keySet()
.stream()
.forEach(System.out::println);
return providerMap;
}
private static Object tenantUrl(String originalUrl, String tenant, String tenantStrategy) throws UnsupportedTenancyException {
if (tenantStrategy.toUpperCase()
.equals("DATABASE")) {
return originalUrl.replace(DEFAULT_DB_NAME, tenant);
} else if (tenantStrategy.toUpperCase()
.equals("SCHEMA")) {
return originalUrl + String.format(SCHEMA_TOKEN, tenant);
} else {
throw new UnsupportedTenancyException("Not yet supported");
}
}
public static final String SCHEMA_TOKEN = ";INIT=CREATE SCHEMA IF NOT EXISTS %1$s\\;SET SCHEMA %1$s";
public static final String DEFAULT_DB_NAME = "mydb1";
}

View File

@@ -1,12 +0,0 @@
package com.baeldung.hibernate.dao;
import java.util.List;
public interface GenericDao<T> {
void save (T entity);
void delete (T Entity);
T findByName(String name);
List<T> findAll();
void populate();
}

View File

@@ -1,80 +0,0 @@
package com.baeldung.hibernate.dao;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import com.baeldung.hibernate.pojo.Supplier;
public class SupplierDao implements GenericDao<Supplier>{
private SessionFactory sessionFactory;
private String tenant;
public SupplierDao(SessionFactory sessionFactory, String tenant) {
this.sessionFactory = sessionFactory;
this.tenant = tenant;
populate();
}
@Override
public void save(Supplier entity) {
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
session.save(entity);
}
@Override
public void delete(Supplier supplier) {
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
session.delete(supplier);
}
@Override
public Supplier findByName(String name) {
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
List<Supplier> fetchedSuppliers = session.createCriteria(Supplier.class).add(Expression.eq("name", name)).list();
if (fetchedSuppliers.size()>0) {
return fetchedSuppliers.get(0);
}else {
return null;
}
}
@Override
public List<Supplier> findAll() {
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
return session.createCriteria(Supplier.class).list();
}
@Override
public void populate() {
System.out.println("Init DB1");
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
session.createSQLQuery("DROP ALL OBJECTS").executeUpdate();
session
.createSQLQuery(
"create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))")
.executeUpdate();
Supplier genertedSupplier = generateEntityForTenant(tenant);
System.out.println("Inserting Supplier"+genertedSupplier);
save (genertedSupplier);
}
private Supplier generateEntityForTenant(String forTenant) {
if (forTenant.equals("mydb1")) {
return new Supplier ("John","USA");
}
return new Supplier ("Miller","UK");
}
}

View File

@@ -1,67 +0,0 @@
package com.baeldung.hibernate.pojo;
// Generated Feb 9, 2017 11:31:36 AM by Hibernate Tools 5.1.0.Final
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.junit.runners.Suite.SuiteClasses;
/**
* Suppliers generated by hbm2java
*/
@Entity(name = "Supplier")
@Table(name ="Supplier")
public class Supplier implements java.io.Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String country;
public Supplier() {
}
public Supplier(String name, String country) {
this.name = name;
this.country = country;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return new StringBuffer().append("[").append(id).append(",").append(name).append(",").append(country).append("]").toString();
}
@Override
public boolean equals(Object obj) {
return name.equals(((Supplier) obj).getName());
}
}