Supporting Multi-tenancy
Applications with Java EE
Rodrigo Cândido da Silva
@rcandidosilva
About Me
• Software Architect
• Java Platform
• JUG Leader of GUJavaSC
• http://gujavasc.org
• Twitter
• @rcandidosilva
• Personal
• http://rodrigocandido.me
Agenda
• Cloud Services Model
• Multi-tenancy
• Concepts
• Challenges
• Java EE + Multi-tenancy
• Tenant Identification
• UI Customization
• Custom Business Rules
• Database Support
• Demo
Cloud Services Model
SaaS Market
Multi-tenancy
• One application
instance to multiple
clients (tenant)
• Inverse of the multiple
instances architecture
Multi-instances vs. Multi-tenant
Multi-instances vs. Multi-tenant
Feature Multi-instances Multi-tenant
Cost Structure Can support only flat
pricing
Supports usage based
pricing
Resources Dedicated resources Shared resources
Operation and
Maintenance
Manage and administer
as many instances as
customers
Manager and administer a
single instance for a
number of customers
Scalable Model Not scalable Scalable
Cloud and Multi-tenancy
Challenges
• Data separation
• UI and business rules customization
• Access control by tenant
• Resource provisioning
• Integrations
• Application update
• Failover tolerance
Pros and Cons
• Pros
• Low maintenance cost
• Same source code for all customers
• High scalability
• Sharing resources between customers
• Cons
• High complexity
• Separation by tenant-id
• More failure risks
• If code breaks -> breaks to all customers
• Low flexibility available to the customers
Multi-tenancy Concepts
• Adoption levels
• Level 1 (Customized)
• Level 2 (Configurable)
• Level 3 (Scalable)
• Database Strategy
• Separate Databases
• Separate Tables
• Shared Database
Level 1 - Customized
• [N] applications and [N] databases
Level 2 - Configurable
• [1] application and [N] databases
Level 3 - Scalable
• [1] application and [1] database
Database Strategy
Separate Databases
Separate Tables
Shared Database
Database Strategy
Feature Separate DBs Separate Tables Shared Database
Data
Customization
Security
Inter-dependency
and Performance
Scalable Model
Customer On-
boarding
What is the Best Choice?
• Depends on…
• Data Customization
• Addition or removal of columns in the data store
• Function Customization
• The functionality executed for a specific business can vary by
customers
• Process Customization
• The business process can vary for each customer
• Licensing Features
• The product has multiple licenses which define the functionality
that is enabled for the customer
Java EE + Multi-tenancy
• Java Servlets
• Tenant Identification
• JavaServer Faces (JSF)
• UI Customization
• Context and Dependency Injection (CDI)
• Custom Business Rules
• Java Persistence API (JPA)
• Database with Multi-tenant Support
Java Servlets
• Tenant Identification
• DNS Resolver
• http://customer1.myapp.com
• http://customer2.myapp.com
• Sub-contexts Resolver
• http://www.myapp.com/customer1
• http://www.myapp.com/customer2
• Login Access Resolver
Java Servlets
public class TenantRequestListener implements ServletRequestListener {
...
@Override
public void requestInitialized(final ServletRequestEvent
servletRequestEvent) {
final HttpServletRequest request = (HttpServletRequest)
servletRequestEvent.getServletRequest();
loadTenant(request);
}
protected void loadTenant(HttpServletRequest request) {
...
}
}
• DNS and Sub-contexts resolver
public class TenantThreadLocal {
public static final ThreadLocal<String> tenantThreadLocal =
new ThreadLocal<String>();
}
JSF + Multi-tenancy
• Flexible software architecture
• Artifacts packaged in separated JAR’s
• Composition at runtime
• Templates and contracts
• Resource library
• Look-and-feel customization
• RenderKit features
• Localization support
JSF Facelets
JSF Multi-templating
• Resource Library Contracts
• Convention
• All available contracts discovered at startup
• Configuration
• faces-config.xml by <resource-library-contract>
• contracts attribute in <f:view>
JSF Multi-templating
<html xmlns="http://www.w3.org/1999/xhtml”
xmlns:h="http://java.sun.com/jsf/html”
xmlns:ui="http://java.sun.com/jsf/
facelets">
<body>
<ui:composition template="#{template}”>
...
</ui:composition>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<context-param>
<param-name>javax.faces.view.TEMPLATE</param-
name>
<param-value>mybusiness</param-value>
</context-param>
</web-app>
CDI + Multi-tenancy
• Custom Business Rules
interface Service {
public void businessMethod();
}
class Customer01Service implements Service {
public void businessMethod() {
...
}
}
class Customer02Service implements Service {
public void businessMethod() {
...
}
}
@Produces
public Service getService() {
switch(currentTenant) {
case "customer01":
return new Customer01Service();
case “customer02":
return new Customer02Service();
}
}
CDI + Multi-tenancy
• Method Interceptors
@Interceptor
@Priority(Interceptor.Priority.APPLICATION)
public class MultiTenantInterceptor {
@AroundInvoke
protected Object invoke(InvocationContext ctx) throws Exception {
...
}
}
<beans xmlns="...">
<interceptors>
<class>MultiTenantInterceptor</class>
</interceptors>
</beans>
JPA + Multi-tenancy
• There is no standard at this time
• EclipseLink
• Multi-tenancy support using @Multitenant
• Multitenant strategies
• @Multitenant(SINGLE_TABLE) – default
• @Multitenant(TABLE_PER_TENANT)
• @Multitenant(VPD)
• Hibernate
• Supports tenant identifier features
• MultiTenantConnectionProvider
• CurrentTenantIdentifierResolver
EclipseLink SINGLE_TABLE
@Entity
@Table(name=“EMP”)
@Multitenant(SINGLE_TABLE)
@TenantDiscriminatorColumn(name = “TENANT_ID”,
contextProperty = “tenant-id”)
public class Employee {
...
}
HashMap properties = new HashMap();
properties.put("tenant.id", "707");
...
EntityManager em = Persistence
.createEntityManagerFactory(
"multi-tenant”,properties)
.createEntityManager();
<persistence-unit name="multi-tenant">
...
<properties>
<property name="tenant.id"
value="707"/>
...
</properties>
</persistence-unit>
EclipseLink TABLE_PER_TENANT
<entity class="Employee">
<multitenant type="TABLE_PER_TENANT">
<tenant-table-discriminator type="SCHEMA" context-
property="eclipselink.tenant-id"/>
</multitenant>
<table name="EMP">
...
</entity>
@Entity
@Table(name=“EMP”)
@Multitenant(TABLE_PER_TENANT)
@TenantTableDiscriminator(type=SCHEMA,
contextProperty="eclipselink.tenant-id")
public class Employee {
...
}
EclipseLink VPD
@Entity
@Multitenant
@TenantDiscriminatorColumn(name = "USER_ID",
contextProperty = "tenant.id")
@Cacheable(false)
public class Task implements Serializable {
...
CALL DBMS_RLS.ADD_POLICY ('SCOTT',
'TASK', 'todo_list_policy', 'SCOTT',
'ident_func', 'select, update, delete'));
<properties>
<property name="eclipselink.session.customizer"
value="example.VPDSessionCustomizer" />
<property name="eclipselink.session-event-listener"
value="example.VPDSessionEventAdapter" />
<property
name="eclipselink.jdbc.exclusive-connection.mode"
value="Always" />
</properties>
Hibernate MultiTenantConnectionProvider
public class MultiTenantProvider
implements MultiTenantConnectionProvider {
public Connection getConnection(String tenantIdentifier)
throws SQLException {
final Connection connection = getAnyConnection();
connection.createStatement().execute(
"SET SCHEMA '" + tenantIdentifier + "'");
return connection;
}
public void releaseConnection(String tenantIdentifier,
Connection connection) throws SQLException {
releaseAnyConnection(connection);
}
}
Hibernate CurrentTenantIdentifierResolver
public class SchemaResolver implements
CurrentTenantIdentifierResolver {
@Override
public String resolveCurrentTenantIdentifier() {
return resolveTenant();
}
@Override
public boolean validateExistingCurrentSessions() {
return false;
}
}
Hibernate persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/
persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://
java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="default">
<properties>
<property name="javax.persistence.provider"
value="org.hibernate.ejb.HibernatePersistence" />
<property name="hibernate.multiTenancy" value="SCHEMA"/>
<property name="hibernate.tenant_identifier_resolver"
value="SchemaResolver"/>
<property name="hibernate.multi_tenant_connection_provider"
value="MultiTenantProvider"/>
</properties>
</persistence-unit>
</persistence>
Demo
• EclipseLink MySports Demo
• http://wiki.eclipse.org/EclipseLink/Examples/MySports
• http://git.eclipse.org/c/eclipselink/examples.git
Questions
?
References
• http://msdn.microsoft.com/en-us/library/aa479086.aspx
• https://developers.google.com/appengine/docs/java/multitenancy/
• http://www.ibm.com/developerworks/java/library/j-multitenant-java/index.html
• http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm
• http://2012.con-fess.com/sessions/-/details/122/JSF-and-JavaEE-7-for-multi-tenant-
applications
• http://jdevelopment.nl/jsf-22/
• http://picketlink.org
• https://developers.google.com/appengine/docs/java/multitenancy/
• http://www.jboss.org/quickstarts/picketlink/picketlink-authentication-idm-multi-tenancy/
• http://wiki.eclipse.org/EclipseLink/Examples/MySports
Thank you!
@rcandidosilva
rodrigocandido.me

ConFoo 2015 - Supporting Multi-tenancy Applications with Java EE

  • 1.
    Supporting Multi-tenancy Applications withJava EE Rodrigo Cândido da Silva @rcandidosilva
  • 2.
    About Me • SoftwareArchitect • Java Platform • JUG Leader of GUJavaSC • http://gujavasc.org • Twitter • @rcandidosilva • Personal • http://rodrigocandido.me
  • 3.
    Agenda • Cloud ServicesModel • Multi-tenancy • Concepts • Challenges • Java EE + Multi-tenancy • Tenant Identification • UI Customization • Custom Business Rules • Database Support • Demo
  • 4.
  • 5.
  • 6.
    Multi-tenancy • One application instanceto multiple clients (tenant) • Inverse of the multiple instances architecture
  • 7.
  • 8.
    Multi-instances vs. Multi-tenant FeatureMulti-instances Multi-tenant Cost Structure Can support only flat pricing Supports usage based pricing Resources Dedicated resources Shared resources Operation and Maintenance Manage and administer as many instances as customers Manager and administer a single instance for a number of customers Scalable Model Not scalable Scalable
  • 9.
  • 10.
    Challenges • Data separation •UI and business rules customization • Access control by tenant • Resource provisioning • Integrations • Application update • Failover tolerance
  • 11.
    Pros and Cons •Pros • Low maintenance cost • Same source code for all customers • High scalability • Sharing resources between customers • Cons • High complexity • Separation by tenant-id • More failure risks • If code breaks -> breaks to all customers • Low flexibility available to the customers
  • 12.
    Multi-tenancy Concepts • Adoptionlevels • Level 1 (Customized) • Level 2 (Configurable) • Level 3 (Scalable) • Database Strategy • Separate Databases • Separate Tables • Shared Database
  • 13.
    Level 1 -Customized • [N] applications and [N] databases
  • 14.
    Level 2 -Configurable • [1] application and [N] databases
  • 15.
    Level 3 -Scalable • [1] application and [1] database
  • 16.
  • 17.
    Database Strategy Feature SeparateDBs Separate Tables Shared Database Data Customization Security Inter-dependency and Performance Scalable Model Customer On- boarding
  • 18.
    What is theBest Choice? • Depends on… • Data Customization • Addition or removal of columns in the data store • Function Customization • The functionality executed for a specific business can vary by customers • Process Customization • The business process can vary for each customer • Licensing Features • The product has multiple licenses which define the functionality that is enabled for the customer
  • 19.
    Java EE +Multi-tenancy • Java Servlets • Tenant Identification • JavaServer Faces (JSF) • UI Customization • Context and Dependency Injection (CDI) • Custom Business Rules • Java Persistence API (JPA) • Database with Multi-tenant Support
  • 20.
    Java Servlets • TenantIdentification • DNS Resolver • http://customer1.myapp.com • http://customer2.myapp.com • Sub-contexts Resolver • http://www.myapp.com/customer1 • http://www.myapp.com/customer2 • Login Access Resolver
  • 21.
    Java Servlets public classTenantRequestListener implements ServletRequestListener { ... @Override public void requestInitialized(final ServletRequestEvent servletRequestEvent) { final HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); loadTenant(request); } protected void loadTenant(HttpServletRequest request) { ... } } • DNS and Sub-contexts resolver public class TenantThreadLocal { public static final ThreadLocal<String> tenantThreadLocal = new ThreadLocal<String>(); }
  • 22.
    JSF + Multi-tenancy •Flexible software architecture • Artifacts packaged in separated JAR’s • Composition at runtime • Templates and contracts • Resource library • Look-and-feel customization • RenderKit features • Localization support
  • 23.
  • 24.
    JSF Multi-templating • ResourceLibrary Contracts • Convention • All available contracts discovered at startup • Configuration • faces-config.xml by <resource-library-contract> • contracts attribute in <f:view>
  • 25.
    JSF Multi-templating <html xmlns="http://www.w3.org/1999/xhtml” xmlns:h="http://java.sun.com/jsf/html” xmlns:ui="http://java.sun.com/jsf/ facelets"> <body> <ui:compositiontemplate="#{template}”> ... </ui:composition> </body> </html> <?xml version="1.0" encoding="UTF-8"?> <web-app> <context-param> <param-name>javax.faces.view.TEMPLATE</param- name> <param-value>mybusiness</param-value> </context-param> </web-app>
  • 26.
    CDI + Multi-tenancy •Custom Business Rules interface Service { public void businessMethod(); } class Customer01Service implements Service { public void businessMethod() { ... } } class Customer02Service implements Service { public void businessMethod() { ... } } @Produces public Service getService() { switch(currentTenant) { case "customer01": return new Customer01Service(); case “customer02": return new Customer02Service(); } }
  • 27.
    CDI + Multi-tenancy •Method Interceptors @Interceptor @Priority(Interceptor.Priority.APPLICATION) public class MultiTenantInterceptor { @AroundInvoke protected Object invoke(InvocationContext ctx) throws Exception { ... } } <beans xmlns="..."> <interceptors> <class>MultiTenantInterceptor</class> </interceptors> </beans>
  • 28.
    JPA + Multi-tenancy •There is no standard at this time • EclipseLink • Multi-tenancy support using @Multitenant • Multitenant strategies • @Multitenant(SINGLE_TABLE) – default • @Multitenant(TABLE_PER_TENANT) • @Multitenant(VPD) • Hibernate • Supports tenant identifier features • MultiTenantConnectionProvider • CurrentTenantIdentifierResolver
  • 29.
    EclipseLink SINGLE_TABLE @Entity @Table(name=“EMP”) @Multitenant(SINGLE_TABLE) @TenantDiscriminatorColumn(name =“TENANT_ID”, contextProperty = “tenant-id”) public class Employee { ... } HashMap properties = new HashMap(); properties.put("tenant.id", "707"); ... EntityManager em = Persistence .createEntityManagerFactory( "multi-tenant”,properties) .createEntityManager(); <persistence-unit name="multi-tenant"> ... <properties> <property name="tenant.id" value="707"/> ... </properties> </persistence-unit>
  • 30.
    EclipseLink TABLE_PER_TENANT <entity class="Employee"> <multitenanttype="TABLE_PER_TENANT"> <tenant-table-discriminator type="SCHEMA" context- property="eclipselink.tenant-id"/> </multitenant> <table name="EMP"> ... </entity> @Entity @Table(name=“EMP”) @Multitenant(TABLE_PER_TENANT) @TenantTableDiscriminator(type=SCHEMA, contextProperty="eclipselink.tenant-id") public class Employee { ... }
  • 31.
    EclipseLink VPD @Entity @Multitenant @TenantDiscriminatorColumn(name ="USER_ID", contextProperty = "tenant.id") @Cacheable(false) public class Task implements Serializable { ... CALL DBMS_RLS.ADD_POLICY ('SCOTT', 'TASK', 'todo_list_policy', 'SCOTT', 'ident_func', 'select, update, delete')); <properties> <property name="eclipselink.session.customizer" value="example.VPDSessionCustomizer" /> <property name="eclipselink.session-event-listener" value="example.VPDSessionEventAdapter" /> <property name="eclipselink.jdbc.exclusive-connection.mode" value="Always" /> </properties>
  • 32.
    Hibernate MultiTenantConnectionProvider public classMultiTenantProvider implements MultiTenantConnectionProvider { public Connection getConnection(String tenantIdentifier) throws SQLException { final Connection connection = getAnyConnection(); connection.createStatement().execute( "SET SCHEMA '" + tenantIdentifier + "'"); return connection; } public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException { releaseAnyConnection(connection); } }
  • 33.
    Hibernate CurrentTenantIdentifierResolver public classSchemaResolver implements CurrentTenantIdentifierResolver { @Override public String resolveCurrentTenantIdentifier() { return resolveTenant(); } @Override public boolean validateExistingCurrentSessions() { return false; } }
  • 34.
    Hibernate persistence.xml <?xml version="1.0"encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/ persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http:// java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="default"> <properties> <property name="javax.persistence.provider" value="org.hibernate.ejb.HibernatePersistence" /> <property name="hibernate.multiTenancy" value="SCHEMA"/> <property name="hibernate.tenant_identifier_resolver" value="SchemaResolver"/> <property name="hibernate.multi_tenant_connection_provider" value="MultiTenantProvider"/> </properties> </persistence-unit> </persistence>
  • 35.
    Demo • EclipseLink MySportsDemo • http://wiki.eclipse.org/EclipseLink/Examples/MySports • http://git.eclipse.org/c/eclipselink/examples.git
  • 36.
  • 37.
    References • http://msdn.microsoft.com/en-us/library/aa479086.aspx • https://developers.google.com/appengine/docs/java/multitenancy/ •http://www.ibm.com/developerworks/java/library/j-multitenant-java/index.html • http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm • http://2012.con-fess.com/sessions/-/details/122/JSF-and-JavaEE-7-for-multi-tenant- applications • http://jdevelopment.nl/jsf-22/ • http://picketlink.org • https://developers.google.com/appengine/docs/java/multitenancy/ • http://www.jboss.org/quickstarts/picketlink/picketlink-authentication-idm-multi-tenancy/ • http://wiki.eclipse.org/EclipseLink/Examples/MySports
  • 38.