Supporting Multi-tenancy Applications with Java EE Rodrigo Cândido da Silva @rcandidosilva JavaOne 2014 CON4959
About Me Brazilian guy ;) Work for Integritas company http://integritastech.com Software Architect Java Platform JUG Leader of GUJavaSC http://gujavasc.org Twitter @rcandidosilva Personal http://rodrigocandido.me
Agenda Cloud Services Model SaaS Market Multi-tenancy Challenges Pros and Cons Implementation Types Java EE + Multi-tenancy Security + Multi-tenancy Cloud + Multi-tenancy Multi-tenancy at JVM
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
Cloud!= Multi-tenancy
Challenges Data separation UI and business rules customization Access control by tenant Resource provisioning Integration 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 Implementation levels Level 1 (Customized) [N] applications and [N] databases Level 2 (Configurable) [1] application and [N] databases Level 3 (Efficient) [N] applications and [1] database Level 4 (Scalable) [1] application and [1] database
Level 1 - Customized [N] applications and [N] databases
Level 2 - Configurable [1] application and [N] databases
Level 3 - Efficient [N] applications and [1] database
Level 4 - Scalable [1] application and [1] database
Java EE + Multi-tenancy Database JPA + Multi-tenancy Customized UI JSF + Multi-tenancy Security Java EE 8 with Cloud support
JPA + Multi-tenancy EclipseLink Multi-tenancy support using @Multitenant Multitenant strategies @Multitenant(SINGLE_TABLE) default @Multitenant(TABLE_PER_TENANT) @Multitenant(VPD) Shared Cache by tenant
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" contextproperty="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 <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> CALL DBMS_RLS.ADD_POLICY ('SCOTT', 'TASK', 'todo_list_policy', 'SCOTT', 'ident_func', 'select, update, delete')); @Entity @Multitenant @TenantDiscriminatorColumn(name = "USER_ID", contextproperty = "tenant.id") @Cacheable(false) public class Task implements Serializable {...
JPA Caching Shared Cache disabled
JPA Caching Shared Cache by tenant
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 support Localization support
JSF Facelets Template File name _template.html Site Navigation The Facelets Gazette Insertion points Events Docs Forums About Contact Site Map Resources css classes, scripts, images
JSF Multi-templating <web-app-root>/contracts contracta Declared contractb Templates Declared Insertion Points Declared Declared contractc Resources Templates Declared Insertion Points Declared Declared Resources Templates Declared Insertion Points Declared Resources JAR files in WEB-INF/lib contractd Declared contracte Templates Declared Insertion Points Declared Declared contractf Resources Templates Declared Insertion Points Declared Declared Resources Templates Declared Insertion Points Declared Resources <web-app-root>/contracts JAR files in WEB-INF/lib contracta Declared contractb Templates Declared Insertion Points Declared Declared contractc Resources Templates Declared Insertion Points Declared Declared Resources Templates Declared Insertion Points Declared Resources contractd Set of available contracts Declared contracte Templates Declared Insertion Points Declared Declared contractf Resources Templates Declared Insertion Points Declared Declared Resources Templates Declared Insertion Points Declared Resources faces-config.xml Facelet 1 Facelet 2 Facelet 3
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</paramname> <param-value>mybusiness</param-value> </context-param> </web-app>
Security + Multi-tenancy PicketLink Java EE security framework Identity Management (IDM) Federation support (SAML, OAuth2, OpenID) Social Login support Multi-tenancy support
Picketlink
Picketlink @Named public class RealmSelector implements Serializable { @Inject private PartitionManager partitionmanager; private Realm realm; } @Produces @PicketLink public Realm select() { return this.realm; } @RequestScoped public class LoginController { @Inject private Identity identity; public String login() { this.identity.login(); } } public String logout() { this.identity.logout(); return "/home.xhtml"; } public class Resources { public enum REALM {acme, umbrella, wayne} @Produces @Named("supportedRealms") public Enum[] supportedrealms() { return REALM.values(); }
Cloud + Multi-tenancy Namespace API com.google.appengine.api.namespacemanager Cloud services support Google Datastore Memcached Task Queue Search
Namespace API // Assuming there is a logged in user. namespace = UserServiceFactory.getUserService().getCurrentUser().getUserId(); NamespaceManager.set(namespace); // Filter to set the Google Apps // domain as the namespace. public class NamespaceFilter implements javax.servlet.filter { @Override public void dofilter(servletrequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { // Make sure set() is only called if the current namespace is not already set. if (NamespaceManager.get() == null) { NamespaceManager.set(NamespaceManager.getGoogleAppsNamespace()); } } } <filter> <filter-name>namespacefilter</filter-name> <filter-class>package.namespacefilter</filter-class> </filter> <filter-mapping> <filter-name>namespacefilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Namespace API Search // Set the current namespace to "aspace" NamespaceManager.set("aSpace"); // Create a SearchService with the namespace "aspace" SearchService searchservice = SearchServiceFactory.getSearchService(); " Memcached // Create a MemcacheService that uses the namespace "abc". MemcacheService explicit = MemcacheServiceFactory.getMemcacheService("abc"); explicit.put("key", value); // stores value in namespace "abc" " Task Queue // Increment the count for the current namespace asynchronously. QueueFactory.getDefaultQueue().add( TaskOptions.Builder.url("/_ah/update_count").param("countName", "SomeRequest"));
Demo Java EE Multi-tenancy sample
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-tenantapplications 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