/* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.activiti.engine.test.cfg.multitenant; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.activiti.engine.ProcessEngine; import org.activiti.engine.impl.asyncexecutor.multitenant.ExecutorPerTenantAsyncExecutor; import org.activiti.engine.impl.asyncexecutor.multitenant.SharedExecutorServiceAsyncExecutor; import org.activiti.engine.impl.cfg.multitenant.MultiSchemaMultiTenantProcessEngineConfiguration; import org.activiti.engine.repository.Deployment; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.h2.jdbcx.JdbcDataSource; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * @author Joram Barrez */ public class MultiTenantProcessEngineTest { private DummyTenantInfoHolder tenantInfoHolder; private MultiSchemaMultiTenantProcessEngineConfiguration config; private ProcessEngine processEngine; @Before public void setup() { setupTenantInfoHolder(); } @After public void close() { processEngine.close(); } private void setupTenantInfoHolder() { DummyTenantInfoHolder tenantInfoHolder = new DummyTenantInfoHolder(); tenantInfoHolder.addTenant("alfresco"); tenantInfoHolder.addUser("alfresco", "joram"); tenantInfoHolder.addUser("alfresco", "tijs"); tenantInfoHolder.addUser("alfresco", "paul"); tenantInfoHolder.addUser("alfresco", "yvo"); tenantInfoHolder.addTenant("acme"); tenantInfoHolder.addUser("acme", "raphael"); tenantInfoHolder.addUser("acme", "john"); tenantInfoHolder.addTenant("starkindustries"); tenantInfoHolder.addUser("starkindustries", "tony"); this.tenantInfoHolder = tenantInfoHolder; } private void setupProcessEngine(boolean sharedExecutor) { config = new MultiSchemaMultiTenantProcessEngineConfiguration(tenantInfoHolder); config.setDatabaseType(MultiSchemaMultiTenantProcessEngineConfiguration.DATABASE_TYPE_H2); config.setDatabaseSchemaUpdate(MultiSchemaMultiTenantProcessEngineConfiguration.DB_SCHEMA_UPDATE_DROP_CREATE); config.setAsyncExecutorEnabled(true); config.setAsyncExecutorActivate(true); if (sharedExecutor) { config.setAsyncExecutor(new SharedExecutorServiceAsyncExecutor(tenantInfoHolder)); } else { config.setAsyncExecutor(new ExecutorPerTenantAsyncExecutor(tenantInfoHolder)); } config.registerTenant("alfresco", createDataSource("jdbc:h2:mem:activiti-mt-alfresco;DB_CLOSE_DELAY=1000", "sa", "")); config.registerTenant("acme", createDataSource("jdbc:h2:mem:activiti-mt-acme;DB_CLOSE_DELAY=1000", "sa", "")); config.registerTenant("starkindustries", createDataSource("jdbc:h2:mem:activiti-mt-stark;DB_CLOSE_DELAY=1000", "sa", "")); processEngine = config.buildProcessEngine(); } @Test public void testStartProcessInstancesWithSharedExecutor() throws Exception { setupProcessEngine(true); runProcessInstanceTest(); } @Test public void testStartProcessInstancesWithExecutorPerTenantAsyncExecutor() throws Exception { setupProcessEngine(false); runProcessInstanceTest(); } private void runProcessInstanceTest() throws InterruptedException { // Generate data startProcessInstances("joram"); startProcessInstances("joram"); startProcessInstances("joram"); startProcessInstances("raphael"); startProcessInstances("raphael"); completeTasks("raphael"); startProcessInstances("tony"); // Verify assertData("joram", 6, 3); assertData("raphael", 0, 0); assertData("tony", 2, 1); // Adding a new tenant tenantInfoHolder.addTenant("dailyplanet"); tenantInfoHolder.addUser("dailyplanet", "louis"); tenantInfoHolder.addUser("dailyplanet", "clark"); config.registerTenant("dailyplanet", createDataSource("jdbc:h2:mem:activiti-mt-daily;DB_CLOSE_DELAY=1000", "sa", "")); // Start process instance for new tenant startProcessInstances("clark"); startProcessInstances("clark"); assertData("clark", 4, 2); // Move the clock 2 hours (jobs fire in one hour) config.getClock().setCurrentTime(new Date(config.getClock().getCurrentTime().getTime() + (2 * 60 * 60 * 1000))); Thread.sleep(15000L); // acquire time is 10 seconds, so 15 should be ok assertData("joram", 6, 0); assertData("raphael", 0, 0); assertData("tony", 2, 0); assertData("clark", 4, 0); } private void startProcessInstances(String userId) { System.out.println(); System.out.println("Starting process instance for user " + userId); tenantInfoHolder.setCurrentUserId(userId); Deployment deployment = processEngine.getRepositoryService().createDeployment() .addClasspathResource("org/activiti/engine/test/cfg/multitenant/oneTaskProcess.bpmn20.xml") .addClasspathResource("org/activiti/engine/test/cfg/multitenant/jobTest.bpmn20.xml") .deploy(); System.out.println("Process deployed! Deployment id is " + deployment.getId()); Map<String, Object> vars = new HashMap<String, Object>(); vars.put("data", "Hello from " + userId); ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey("oneTaskProcess", vars); List<Task> tasks = processEngine.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).list(); System.out.println("Got " + tasks.size() + " tasks"); System.out.println("Got " + processEngine.getHistoryService().createHistoricProcessInstanceQuery().count() + " process instances in the system"); // Start a process instance with a Job processEngine.getRuntimeService().startProcessInstanceByKey("jobTest"); tenantInfoHolder.clearCurrentUserId(); tenantInfoHolder.clearCurrentTenantId(); } private void completeTasks(String userId) { tenantInfoHolder.setCurrentUserId(userId); for (Task task : processEngine.getTaskService().createTaskQuery().list()) { processEngine.getTaskService().complete(task.getId()); } tenantInfoHolder.clearCurrentUserId(); tenantInfoHolder.clearCurrentTenantId(); } private void assertData(String userId, long nrOfActiveProcessInstances, long nrOfActiveJobs) { tenantInfoHolder.setCurrentUserId(userId); Assert.assertEquals(nrOfActiveProcessInstances, processEngine.getRuntimeService().createProcessInstanceQuery().count()); Assert.assertEquals(nrOfActiveProcessInstances, processEngine.getHistoryService().createHistoricProcessInstanceQuery().unfinished().count()); Assert.assertEquals(nrOfActiveJobs, processEngine.getManagementService().createJobQuery().count()); tenantInfoHolder.clearCurrentUserId(); tenantInfoHolder.clearCurrentTenantId(); } // Helper ////////////////////////////////////////// private DataSource createDataSource(String jdbcUrl, String jdbcUsername, String jdbcPassword) { JdbcDataSource ds = new JdbcDataSource(); ds.setURL(jdbcUrl); ds.setUser(jdbcUsername); ds.setPassword(jdbcPassword); return ds; } }