From ec712af5f0d35673f28addc6f6e039988fba2f35 Mon Sep 17 00:00:00 2001 From: Abhi Bavishi Date: Fri, 12 Jun 2015 12:43:10 +0530 Subject: [PATCH] First commmit for Spring Multi-tenancy with Hibernate example. --- .../baeldung/multitenancy/entities/Book.java | 19 ++++ ...urrentSessionTenantIdentifierResolver.java | 33 ++++++ .../implementation/SessionFactoryBean.java | 50 +++++++++ .../SimpleMultiTenantConnectionProvider.java | 35 ++++++ .../service/MultiTenantService.java | 38 +++++++ .../resources/applicationContext.xml | 105 ++++++++++++++++++ .../resources/database.properties | 1 + 7 files changed, 281 insertions(+) create mode 100644 spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/entities/Book.java create mode 100644 spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/CurrentSessionTenantIdentifierResolver.java create mode 100644 spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SessionFactoryBean.java create mode 100644 spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SimpleMultiTenantConnectionProvider.java create mode 100644 spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/service/MultiTenantService.java create mode 100644 spring-all/src/main/java/org/baeldung/multi-tenancy/resources/applicationContext.xml create mode 100644 spring-all/src/main/java/org/baeldung/multi-tenancy/resources/database.properties diff --git a/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/entities/Book.java b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/entities/Book.java new file mode 100644 index 0000000000..88cfda8013 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/entities/Book.java @@ -0,0 +1,19 @@ +package com.baeldung.multitenancy.entities; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +@Entity +public class Book { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + Long id; + + @NotNull + @Column(name = "name") + String name; + + // standard getters and setters +} diff --git a/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/CurrentSessionTenantIdentifierResolver.java b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/CurrentSessionTenantIdentifierResolver.java new file mode 100644 index 0000000000..41eddcd291 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/CurrentSessionTenantIdentifierResolver.java @@ -0,0 +1,33 @@ +package com.baeldung.multitenancy.implementation; + +import org.hibernate.context.spi.CurrentTenantIdentifierResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.servlet.http.HttpServletRequest; +import java.text.MessageFormat; + +/** + * CurrentSessionTenantIdentifierResolver-- here we fetch the tenantId from the request. + * User: baeldung + * Date: 9/06/15 + */ + +public class CurrentSessionTenantIdentifierResolver implements CurrentTenantIdentifierResolver { + + @Autowired + private HttpServletRequest request; + + @Override + public String resolveCurrentTenantIdentifier() { + String tenantId = request.getHeader("X-TenantId"); + return tenantId; + } + + @Override + public boolean validateExistingCurrentSessions() { + // Additional logic to ensure appropriate connections are made. + return false; + } +} diff --git a/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SessionFactoryBean.java b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SessionFactoryBean.java new file mode 100644 index 0000000000..48b371d9ae --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SessionFactoryBean.java @@ -0,0 +1,50 @@ +package com.baeldung.multitenancy.implementation; + +import org.hibernate.tool.hbm2ddl.SchemaExport; + +import javax.sql.DataSource; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +/** + * Created with IntelliJ IDEA. + * User: vtajzich + * Date: 8/21/13 + */ +public class SessionFactoryBean extends org.springframework.orm.hibernate4.LocalSessionFactoryBean { + + private Map dataSourceMap; + + @Override + public void afterPropertiesSet() throws IOException { + super.afterPropertiesSet(); + + for (Map.Entry entry : dataSourceMap.entrySet()) { + + Connection connection = null; + + try { + + connection = entry.getValue().getConnection(); + + SchemaExport export = new SchemaExport(getConfiguration(), connection); + + export.setOutputFile(entry.getKey() + "-schema.sql"); + export.setDelimiter(";"); + + // define your rules, here. + //The below code allows creation, but does not allow dropping entries + export.execute(true, true, false, true); + + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + public void setDataSourceMap(Map dataSourceMap) { + this.dataSourceMap = dataSourceMap; + } +} diff --git a/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SimpleMultiTenantConnectionProvider.java b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SimpleMultiTenantConnectionProvider.java new file mode 100644 index 0000000000..b83f42d1ca --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/implementation/SimpleMultiTenantConnectionProvider.java @@ -0,0 +1,35 @@ +package com.baeldung.multitenancy.implementation; + +import org.hibernate.service.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl; + +import javax.sql.DataSource; +import java.util.Map; + +/** + * CurrentSessionTenantIdentifierResolver-- here we fetch the DB conection for the given tenantIdentifier. + * User: baeldung + * Date: 9/06/15 + */ + +public class SimpleMultiTenantConnectionProvider extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl { + + private Map dataSourceMap; + + @Override + protected DataSource selectAnyDataSource() { + return (DataSource) dataSourceMap.values().toArray()[0]; + } + + @Override + protected DataSource selectDataSource(String tenantIdentifier) { + return dataSourceMap.get(tenantIdentifier); + } + + public Map getDataSourceMap() { + return dataSourceMap; + } + + public void setDataSourceMap(Map dataSourceMap) { + this.dataSourceMap = dataSourceMap; + } +} diff --git a/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/service/MultiTenantService.java b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/service/MultiTenantService.java new file mode 100644 index 0000000000..a9e14f4144 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/multi-tenancy/java/com/baeldung/multitenancy/service/MultiTenantService.java @@ -0,0 +1,38 @@ +package com.baeldung.multitenancy.service; + +import com.baeldung.multitenancy.entities.Book; +import org.hibernate.SessionFactory; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * MultitenantService-- we use the SessionFactory to save and fetch entities. + * User: baeldung + * Date: 9/06/15 + */ + +@Service +public class MultiTenantService { + + @AutoWired + private SessionFactory sessionFactory; + + public void save(Book book) { + sessionFactory.getCurrentSession().save(book); + } + + public Book findBook(Long id) { + return (Book) sessionFactory. + getCurrentSession().get(Book.class, id); + } + + public List findAllBooks() { + return sessionFactory. + getCurrentSession().createQuery("from Books").list(); + } + + public void setSessionFactory(SessionFactory sessionFactory){ + this.sessionFactory = sessionFactory; + } +} diff --git a/spring-all/src/main/java/org/baeldung/multi-tenancy/resources/applicationContext.xml b/spring-all/src/main/java/org/baeldung/multi-tenancy/resources/applicationContext.xml new file mode 100644 index 0000000000..dfdd2bd346 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/multi-tenancy/resources/applicationContext.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-all/src/main/java/org/baeldung/multi-tenancy/resources/database.properties b/spring-all/src/main/java/org/baeldung/multi-tenancy/resources/database.properties new file mode 100644 index 0000000000..8e7cdcbf54 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/multi-tenancy/resources/database.properties @@ -0,0 +1 @@ +database.driverClassName=com.mysql.jdbc.Driver