From 6f26cc8bd790ab9171e1fb4adeac118131a24885 Mon Sep 17 00:00:00 2001 From: Valentin Zickner Date: Tue, 17 Mar 2026 09:40:09 +0100 Subject: [PATCH 1/5] introduce MailClientProvider for dynamic mail client generation --- .../cmmn/engine/CmmnEngineConfiguration.java | 47 ++++-- .../impl/mail/CmmnMailActivityDelegate.java | 14 +- .../cmmn/test/task/CmmnEmailTestCase.java | 99 +++++++++++ .../cmmn/test/task/CmmnMailTaskTest.java | 42 +---- ...mmnMailTaskWithMailClientProviderTest.java | 154 +++++++++++++++++ ...ClientProviderTest.testSimpleTextMail.cmmn | 33 ++++ .../cfg/mail/DefaultMailClientProvider.java | 59 +++++++ .../engine/ProcessEngineConfiguration.java | 34 +++- .../bpmn/mail/BpmnMailActivityDelegate.java | 14 +- .../cfg/ProcessEngineConfigurationImpl.java | 15 +- ...ailSendTaskWithMailClientProviderTest.java | 155 ++++++++++++++++++ .../common/api/client/MailClientProvider.java | 34 ++++ 12 files changed, 629 insertions(+), 71 deletions(-) create mode 100644 modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java create mode 100644 modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java create mode 100644 modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn create mode 100644 modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java create mode 100644 modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java create mode 100644 modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java index 99192355cb1..01fe8c3a956 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java @@ -296,7 +296,9 @@ import org.flowable.job.service.impl.asyncexecutor.ExecuteAsyncRunnableFactory; import org.flowable.job.service.impl.asyncexecutor.FailedJobCommandFactory; import org.flowable.job.service.impl.asyncexecutor.JobManager; +import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; import org.flowable.mail.common.api.client.FlowableMailClient; +import org.flowable.mail.common.api.client.MailClientProvider; import org.flowable.task.service.InternalTaskAssignmentManager; import org.flowable.task.service.InternalTaskVariableScopeResolver; import org.flowable.task.service.TaskPostProcessor; @@ -526,11 +528,10 @@ public class CmmnEngineConfiguration extends AbstractBuildableEngineConfiguratio protected HttpClientConfig httpClientConfig = new HttpClientConfig(); // Email - protected FlowableMailClient defaultMailClient; + protected MailClientProvider mailClientProvider = new DefaultMailClientProvider(); protected MailServerInfo defaultMailServer; protected String mailSessionJndi; protected Map mailServers = new HashMap<>(); - protected Map mailClients = new HashMap<>(); protected Map mailSessionsJndi = new HashMap<>(); // Async executor @@ -929,17 +930,23 @@ public void initExpressionManager() { } public void initMailClients() { - if (defaultMailClient == null) { + if (mailClientProvider == null) { + mailClientProvider = new DefaultMailClientProvider(); + } + if (!(mailClientProvider instanceof DefaultMailClientProvider defaultMailClientProvider)) { + return; // custom provider handles resolution at runtime + } + if (defaultMailClientProvider.getDefaultMailClient() == null) { String sessionJndi = getMailSessionJndi(); if (sessionJndi != null) { - defaultMailClient = FlowableMailClientCreator.createSessionClient(sessionJndi, getDefaultMailServer()); + defaultMailClientProvider.setDefaultMailClient(FlowableMailClientCreator.createSessionClient(sessionJndi, getDefaultMailServer())); } else { MailServerInfo mailServer = getDefaultMailServer(); String host = mailServer.getMailServerHost(); if (host == null) { throw new FlowableException("no SMTP host is configured for the default mail server"); } - defaultMailClient = FlowableMailClientCreator.createHostClient(host, mailServer); + defaultMailClientProvider.setDefaultMailClient(FlowableMailClientCreator.createHostClient(host, mailServer)); } } @@ -947,6 +954,7 @@ public void initMailClients() { tenantIds.addAll(mailServers.keySet()); if (!tenantIds.isEmpty()) { + Map mailClients = defaultMailClientProvider.getMailClients(); MailServerInfo defaultMailServer = getDefaultMailServer(); for (String tenantId : tenantIds) { if (mailClients.containsKey(tenantId)) { @@ -4078,12 +4086,26 @@ public CmmnEngineConfiguration setHttpClientConfig(HttpClientConfig httpClientCo return this; } + public MailClientProvider getMailClientProvider() { + return mailClientProvider; + } + + public CmmnEngineConfiguration setMailClientProvider(MailClientProvider mailClientProvider) { + this.mailClientProvider = mailClientProvider; + return this; + } + public FlowableMailClient getDefaultMailClient() { - return defaultMailClient; + if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + return defaultProvider.getDefaultMailClient(); + } + return null; } public CmmnEngineConfiguration setDefaultMailClient(FlowableMailClient defaultMailClient) { - this.defaultMailClient = defaultMailClient; + if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + defaultProvider.setDefaultMailClient(defaultMailClient); + } return this; } @@ -4220,16 +4242,21 @@ public MailServerInfo getMailServer(String tenantId) { } public Map getMailClients() { - return mailClients; + if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + return defaultProvider.getMailClients(); + } + return new HashMap<>(); } public CmmnEngineConfiguration setMailClients(Map mailClients) { - this.mailClients = mailClients; + if (this.mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + defaultProvider.getMailClients().putAll(mailClients); + } return this; } public FlowableMailClient getMailClient(String tenantId) { - return mailClients.get(tenantId); + return mailClientProvider.getMailClient(tenantId); } public Map getMailSessionsJndi() { diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java index 5e648fed27c..97d109eedc7 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java @@ -21,6 +21,7 @@ import org.flowable.common.engine.impl.mail.BaseMailActivityDelegate; import org.flowable.content.api.ContentService; import org.flowable.mail.common.api.client.FlowableMailClient; +import org.flowable.mail.common.api.client.MailClientProvider; /** * @author Filip Hrisafov @@ -37,12 +38,15 @@ protected FlowableMailClient getMailClient(DelegatePlanItemInstance planItemInst CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(); String tenantId = planItemInstance.getTenantId(); FlowableMailClient mailClient = null; - if (StringUtils.isNotBlank(tenantId)) { - mailClient = cmmnEngineConfiguration.getMailClient(tenantId); - } - if (mailClient == null) { - mailClient = cmmnEngineConfiguration.getDefaultMailClient(); + MailClientProvider mailClientProvider = cmmnEngineConfiguration.getMailClientProvider(); + if (mailClientProvider != null) { + if (StringUtils.isNotBlank(tenantId)) { + mailClient = mailClientProvider.getMailClient(tenantId); + } + if (mailClient == null) { + mailClient = mailClientProvider.getMailClient(null); + } } return mailClient; diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java new file mode 100644 index 00000000000..e5d33628fb8 --- /dev/null +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java @@ -0,0 +1,99 @@ +/* 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.flowable.cmmn.test.task; + +import java.util.HashMap; +import java.util.Map; + +import org.flowable.cmmn.test.FlowableCmmnTestCase; +import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; +import org.flowable.mail.common.api.client.MailClientProvider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.subethamail.wiser.Wiser; + +/** + * @author Valentin Zickner + */ +@Tag("email") +public abstract class CmmnEmailTestCase extends FlowableCmmnTestCase { + + protected static Wiser wiser; + private MailClientProvider initialMailClientProvider; + private Map initialMailServers; + + @BeforeAll + public static void setupWiser() throws Exception { + int counter = 0; + boolean serverUpAndRunning = false; + while (!serverUpAndRunning && counter++ < 11) { + wiser = Wiser.port(5025); + try { + wiser.start(); + serverUpAndRunning = true; + } catch (RuntimeException e) { // Fix for slow port-closing Jenkins + if (e.getMessage().toLowerCase().contains("bindexception")) { + Thread.sleep(250L); + } + } + } + } + + @BeforeEach + public void setUp() { + wiser.getMessages().clear(); + initialMailClientProvider = cmmnEngineConfiguration.getMailClientProvider(); + Map mailServers = cmmnEngineConfiguration.getMailServers(); + initialMailServers = mailServers == null ? null : new HashMap<>(mailServers); + } + + @AfterEach + public void tearDown() { + cmmnEngineConfiguration.setMailClientProvider(initialMailClientProvider); + if (initialMailServers != null) { + cmmnEngineConfiguration.getMailServers().clear(); + cmmnEngineConfiguration.getMailServers().putAll(initialMailServers); + } + reinitializeMailClients(); + } + + @AfterAll + public static void stopWiser() { + wiser.stop(); + } + + protected void reinitializeMailClients() { + cmmnEngineConfiguration.setDefaultMailClient(null); + cmmnEngineConfiguration.getMailClients().clear(); + cmmnEngineConfiguration.setMailClientProvider(null); + cmmnEngineConfiguration.initMailClients(); + } + + protected void addMailServer(String tenantId, String defaultFrom, String forceTo) { + MailServerInfo mailServerInfo = new MailServerInfo(); + mailServerInfo.setMailServerHost("localhost"); + mailServerInfo.setMailServerPort(5025); + mailServerInfo.setMailServerUseSSL(false); + mailServerInfo.setMailServerUseTLS(false); + mailServerInfo.setMailServerDefaultFrom(defaultFrom); + mailServerInfo.setMailServerForceTo(forceTo); + mailServerInfo.setMailServerUsername(defaultFrom); + mailServerInfo.setMailServerPassword("password"); + + cmmnEngineConfiguration.getMailServers().put(tenantId, mailServerInfo); + } + +} diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskTest.java index 89dc3248071..668bfb74d33 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskTest.java @@ -33,15 +33,9 @@ import org.apache.commons.lang3.Validate; import org.flowable.cmmn.engine.test.CmmnDeployment; -import org.flowable.cmmn.test.FlowableCmmnTestCase; import org.flowable.common.engine.impl.cfg.mail.FlowableMailClientCreator; import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import org.subethamail.wiser.Wiser; import org.subethamail.wiser.WiserMessage; import tools.jackson.databind.node.ArrayNode; @@ -49,41 +43,7 @@ /** * @author Joram Barrez */ -@Tag("email") -public class CmmnMailTaskTest extends FlowableCmmnTestCase { - - protected static Wiser wiser; - - @BeforeAll - public static void setupWiser() throws Exception { - wiser = Wiser.port(5025); - - int counter = 0; - boolean serverUpAndRunning = false; - while (!serverUpAndRunning && counter++ < 11) { - - wiser = Wiser.port(5025); - - try { - wiser.start(); - serverUpAndRunning = true; - } catch (RuntimeException e) { // Fix for slow port-closing Jenkins - if (e.getMessage().toLowerCase().contains("bindexception")) { - Thread.sleep(250L); - } - } - } - } - - @BeforeEach - public void resetMessages() { - wiser.getMessages().clear(); - } - - @AfterAll - public static void stopWiser() { - wiser.stop(); - } +public class CmmnMailTaskTest extends CmmnEmailTestCase { @Test @CmmnDeployment diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java new file mode 100644 index 00000000000..a787872c4fa --- /dev/null +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java @@ -0,0 +1,154 @@ +/* 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.flowable.cmmn.test.task; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.flowable.cmmn.engine.test.CmmnDeployment; +import org.flowable.common.engine.impl.cfg.mail.FlowableMailClientCreator; +import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; +import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; +import org.flowable.mail.common.api.client.FlowableMailClient; +import org.flowable.mail.common.api.client.MailClientProvider; +import org.junit.jupiter.api.Test; +import org.subethamail.wiser.WiserMessage; + +/** + * Tests for the {@link MailClientProvider} integration in the CMMN engine. + * + * @author Valentin Zickner + */ +public class CmmnMailTaskWithMailClientProviderTest extends CmmnEmailTestCase { + + private static final String CMMN_RESOURCE = "org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn"; + + @Test + @CmmnDeployment(resources = CMMN_RESOURCE) + public void testProviderReturnsClientForNullTenantId() { + FlowableMailClient providerClient = createMailClient("provider-default@flowable.org"); + cmmnEngineConfiguration.setMailClientProvider(requestedTenantId -> { + if (requestedTenantId == null) { + return providerClient; + } + return null; + }); + + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("testSimpleTextMail") + .start(); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-default@flowable.org"); + } + + @Test + public void testProviderReturnsClientForTenant() { + String tenantId = "providerTenant"; + + FlowableMailClient tenantClient = createMailClient("provider-tenant@flowable.org"); + cmmnEngineConfiguration.setMailClientProvider(requestedTenantId -> { + if (tenantId.equals(requestedTenantId)) { + return tenantClient; + } + return null; + }); + + String deploymentId = cmmnRepositoryService.createDeployment() + .addClasspathResource(CMMN_RESOURCE) + .tenantId(tenantId) + .deploy() + .getId(); + + try { + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("testSimpleTextMail") + .tenantId(tenantId) + .start(); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-tenant@flowable.org"); + } finally { + cmmnRepositoryService.deleteDeployment(deploymentId, true); + } + } + + @Test + @CmmnDeployment(resources = CMMN_RESOURCE) + public void testDefaultProviderFallsBackToDefaultClient() { + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("testSimpleTextMail") + .start(); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + // DefaultMailClientProvider should resolve the default mail client + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("flowable@localhost"); + } + + @Test + public void testDefaultProviderResolvesTenantFromStaticConfig() { + String tenantId = "staticTenant"; + addMailServer(tenantId, "static-tenant@flowable.org", null); + reinitializeMailClients(); + + String deploymentId = cmmnRepositoryService.createDeployment() + .addClasspathResource(CMMN_RESOURCE) + .tenantId(tenantId) + .deploy() + .getId(); + + try { + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("testSimpleTextMail") + .tenantId(tenantId) + .start(); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("static-tenant@flowable.org"); + } finally { + cmmnRepositoryService.deleteDeployment(deploymentId, true); + } + } + + @Test + @CmmnDeployment(resources = CMMN_RESOURCE) + public void testDefaultMailClientProviderIsSetByDefault() { + assertThat(cmmnEngineConfiguration.getMailClientProvider()).isInstanceOf(DefaultMailClientProvider.class); + + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("testSimpleTextMail") + .start(); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("flowable@localhost"); + } + + protected FlowableMailClient createMailClient(String defaultFrom) { + MailServerInfo mailServerInfo = new MailServerInfo(); + mailServerInfo.setMailServerHost("localhost"); + mailServerInfo.setMailServerPort(5025); + mailServerInfo.setMailServerUseSSL(false); + mailServerInfo.setMailServerUseTLS(false); + mailServerInfo.setMailServerDefaultFrom(defaultFrom); + mailServerInfo.setMailServerUsername(defaultFrom); + mailServerInfo.setMailServerPassword("password"); + return FlowableMailClientCreator.createHostClient("localhost", mailServerInfo); + } + +} diff --git a/modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn b/modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn new file mode 100644 index 00000000000..62a505ddc41 --- /dev/null +++ b/modules/flowable-cmmn-engine/src/test/resources/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java new file mode 100644 index 00000000000..ce78b8f5355 --- /dev/null +++ b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java @@ -0,0 +1,59 @@ +/* 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.flowable.common.engine.impl.cfg.mail; + +import java.util.HashMap; +import java.util.Map; + +import org.flowable.mail.common.api.client.FlowableMailClient; +import org.flowable.mail.common.api.client.MailClientProvider; + +/** + * Default implementation of {@link MailClientProvider} that resolves mail clients from + * a static map keyed by tenant identifier, with a fallback to a default mail client. + * + * @author Valentin Zickner + */ +public class DefaultMailClientProvider implements MailClientProvider { + + protected FlowableMailClient defaultMailClient; + protected final Map tenantMailClients; + + public DefaultMailClientProvider() { + this.tenantMailClients = new HashMap<>(); + } + + @Override + public FlowableMailClient getMailClient(String tenantId) { + if (tenantId != null) { + FlowableMailClient client = tenantMailClients.get(tenantId); + if (client != null) { + return client; + } + } + return defaultMailClient; + } + + public FlowableMailClient getDefaultMailClient() { + return defaultMailClient; + } + + public void setDefaultMailClient(FlowableMailClient defaultMailClient) { + this.defaultMailClient = defaultMailClient; + } + + public Map getMailClients() { + return tenantMailClients; + } + +} diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java b/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java index 40752fd6af8..c335b84ea5d 100755 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java @@ -33,7 +33,9 @@ import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration; import org.flowable.image.ProcessDiagramGenerator; import org.flowable.job.service.impl.asyncexecutor.AsyncExecutor; +import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; import org.flowable.mail.common.api.client.FlowableMailClient; +import org.flowable.mail.common.api.client.MailClientProvider; import org.flowable.task.service.TaskPostProcessor; /** @@ -89,11 +91,10 @@ public abstract class ProcessEngineConfiguration extends AbstractBuildableEngine protected boolean asyncExecutorActivate; protected boolean asyncHistoryExecutorActivate; - protected FlowableMailClient defaultMailClient; + protected MailClientProvider mailClientProvider = new DefaultMailClientProvider(); protected MailServerInfo defaultMailServer; protected String mailSessionJndi; protected Map mailServers = new HashMap<>(); - protected Map mailClients = new HashMap<>(); protected Map mailSessionsJndi = new HashMap<>(); // Set Http Client config defaults @@ -245,12 +246,26 @@ public ProcessEngineConfiguration setHistory(String history) { return this; } + public MailClientProvider getMailClientProvider() { + return mailClientProvider; + } + + public ProcessEngineConfiguration setMailClientProvider(MailClientProvider mailClientProvider) { + this.mailClientProvider = mailClientProvider; + return this; + } + public FlowableMailClient getDefaultMailClient() { - return defaultMailClient; + if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + return defaultProvider.getDefaultMailClient(); + } + return null; } public ProcessEngineConfiguration setDefaultMailClient(FlowableMailClient defaultMailClient) { - this.defaultMailClient = defaultMailClient; + if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + defaultProvider.setDefaultMailClient(defaultMailClient); + } return this; } @@ -387,15 +402,20 @@ public ProcessEngineConfiguration setMailServers(Map mai } public FlowableMailClient getMailClient(String tenantId) { - return mailClients.get(tenantId); + return mailClientProvider.getMailClient(tenantId); } public Map getMailClients() { - return mailClients; + if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + return defaultProvider.getMailClients(); + } + return new HashMap<>(); } public ProcessEngineConfiguration setMailClients(Map mailClients) { - this.mailClients.putAll(mailClients); + if (this.mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { + defaultProvider.getMailClients().putAll(mailClients); + } return this; } diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java index ba8e767d288..61e50985ed3 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java @@ -21,6 +21,7 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.mail.common.api.client.FlowableMailClient; +import org.flowable.mail.common.api.client.MailClientProvider; /** * @author Filip Hrisafov @@ -38,12 +39,15 @@ protected FlowableMailClient getMailClient(DelegateExecution execution) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); String tenantId = execution.getTenantId(); FlowableMailClient mailClient = null; - if (StringUtils.isNotBlank(tenantId)) { - mailClient = processEngineConfiguration.getMailClient(tenantId); - } - if (mailClient == null) { - mailClient = processEngineConfiguration.getDefaultMailClient(); + MailClientProvider mailClientProvider = processEngineConfiguration.getMailClientProvider(); + if (mailClientProvider != null) { + if (StringUtils.isNotBlank(tenantId)) { + mailClient = mailClientProvider.getMailClient(tenantId); + } + if (mailClient == null) { + mailClient = mailClientProvider.getMailClient(null); + } } return mailClient; diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/cfg/ProcessEngineConfigurationImpl.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/cfg/ProcessEngineConfigurationImpl.java index 935cf749e2e..c883c412c96 100755 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/cfg/ProcessEngineConfigurationImpl.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/cfg/ProcessEngineConfigurationImpl.java @@ -389,6 +389,8 @@ import org.flowable.job.service.impl.asyncexecutor.ExecuteAsyncRunnableFactory; import org.flowable.job.service.impl.asyncexecutor.FailedJobCommandFactory; import org.flowable.job.service.impl.asyncexecutor.JobManager; +import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; +import org.flowable.mail.common.api.client.FlowableMailClient; import org.flowable.task.api.TaskQueryInterceptor; import org.flowable.task.api.history.HistoricTaskQueryInterceptor; import org.flowable.task.service.InternalTaskAssignmentManager; @@ -2352,17 +2354,23 @@ public void initExpressionManager() { } public void initMailClients() { - if (defaultMailClient == null) { + if (mailClientProvider == null) { + mailClientProvider = new DefaultMailClientProvider(); + } + if (!(mailClientProvider instanceof DefaultMailClientProvider defaultMailClientProvider)) { + return; // custom provider handles resolution at runtime + } + if (defaultMailClientProvider.getDefaultMailClient() == null) { String sessionJndi = getMailSessionJndi(); if (sessionJndi != null) { - defaultMailClient = FlowableMailClientCreator.createSessionClient(sessionJndi, getDefaultMailServer()); + defaultMailClientProvider.setDefaultMailClient(FlowableMailClientCreator.createSessionClient(sessionJndi, getDefaultMailServer())); } else { MailServerInfo mailServer = getDefaultMailServer(); String host = mailServer.getMailServerHost(); if (host == null) { throw new FlowableException("no SMTP host is configured for the default mail server"); } - defaultMailClient = FlowableMailClientCreator.createHostClient(host, mailServer); + defaultMailClientProvider.setDefaultMailClient(FlowableMailClientCreator.createHostClient(host, mailServer)); } } @@ -2370,6 +2378,7 @@ public void initMailClients() { tenantIds.addAll(mailServers.keySet()); if (!tenantIds.isEmpty()) { + Map mailClients = defaultMailClientProvider.getMailClients(); MailServerInfo defaultMailServer = getDefaultMailServer(); for (String tenantId : tenantIds) { if (mailClients.containsKey(tenantId)) { diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java new file mode 100644 index 00000000000..fb67e10b2e5 --- /dev/null +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java @@ -0,0 +1,155 @@ +/* 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.flowable.engine.test.bpmn.mail; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.flowable.common.engine.impl.cfg.mail.FlowableMailClientCreator; +import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; +import org.flowable.engine.test.Deployment; +import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; +import org.flowable.mail.common.api.client.FlowableMailClient; +import org.flowable.mail.common.api.client.MailClientProvider; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.subethamail.wiser.WiserMessage; + +/** + * Tests for the {@link MailClientProvider} integration in the BPMN engine. + * + * @author Valentin Zickner + */ +public class EmailSendTaskWithMailClientProviderTest extends EmailTestCase { + + protected MailClientProvider initialMailClientProvider; + + @BeforeEach + void saveProvider() { + initialMailClientProvider = processEngineConfiguration.getMailClientProvider(); + } + + @AfterEach + void restoreProvider() { + processEngineConfiguration.setMailClientProvider(initialMailClientProvider); + reinitilizeMailClients(); + } + + @Test + public void testProviderReturnsClientForTenant() throws Exception { + String tenantId = "providerTenant"; + + FlowableMailClient tenantClient = createMailClient("provider-tenant@flowable.org"); + processEngineConfiguration.setMailClientProvider(requestedTenantId -> { + if (tenantId.equals(requestedTenantId)) { + return tenantClient; + } + return null; + }); + + String deploymentId = repositoryService.createDeployment() + .addClasspathResource("org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") + .tenantId(tenantId) + .deploy() + .getId(); + + try { + runtimeService.startProcessInstanceByKeyAndTenantId("simpleTextOnly", tenantId); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-tenant@flowable.org"); + } finally { + deleteDeployment(deploymentId); + } + } + + @Test + public void testDefaultProviderResolvesTenantFromStaticConfig() throws Exception { + String tenantId = "staticTenant"; + addMailServer(tenantId, "static-tenant@flowable.org", null); + reinitilizeMailClients(); + + String deploymentId = repositoryService.createDeployment() + .addClasspathResource("org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") + .tenantId(tenantId) + .deploy() + .getId(); + + try { + runtimeService.startProcessInstanceByKeyAndTenantId("simpleTextOnly", tenantId); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("static-tenant@flowable.org"); + } finally { + deleteDeployment(deploymentId); + } + } + + @Test + @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") + public void testProviderReturnsClientForNullTenantId() throws Exception { + FlowableMailClient defaultProviderClient = createMailClient("provider-default@flowable.org"); + processEngineConfiguration.setMailClientProvider(requestedTenantId -> { + if (requestedTenantId == null) { + return defaultProviderClient; + } + return null; + }); + + runtimeService.startProcessInstanceByKey("simpleTextOnly"); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-default@flowable.org"); + } + + @Test + @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") + public void testDefaultProviderFallsBackToDefaultClient() throws Exception { + runtimeService.startProcessInstanceByKey("simpleTextOnly"); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + // DefaultMailClientProvider should resolve the default mail client (flowable@localhost from test config) + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("flowable@localhost"); + } + + @Test + @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") + public void testDefaultMailClientProviderIsSetByDefault() throws Exception { + assertThat(processEngineConfiguration.getMailClientProvider()).isInstanceOf(DefaultMailClientProvider.class); + + runtimeService.startProcessInstanceByKey("simpleTextOnly"); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("flowable@localhost"); + } + + protected FlowableMailClient createMailClient(String defaultFrom) { + MailServerInfo mailServerInfo = new MailServerInfo(); + mailServerInfo.setMailServerHost("localhost"); + mailServerInfo.setMailServerPort(5025); + mailServerInfo.setMailServerUseSSL(false); + mailServerInfo.setMailServerUseTLS(false); + mailServerInfo.setMailServerDefaultFrom(defaultFrom); + mailServerInfo.setMailServerUsername(defaultFrom); + mailServerInfo.setMailServerPassword("password"); + return FlowableMailClientCreator.createHostClient("localhost", mailServerInfo); + } + +} diff --git a/modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java b/modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java new file mode 100644 index 00000000000..f0d26f00c4e --- /dev/null +++ b/modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java @@ -0,0 +1,34 @@ +/* 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.flowable.mail.common.api.client; + +/** + * Provider for dynamically resolving {@link FlowableMailClient} instances. + *

+ * This allows mail client resolution to be dynamic rather than statically configured at engine startup. + * For example, this can be used to support dynamically added tenants or configuration changes at runtime. + *

+ * Implementations must be thread-safe, as this provider may be called concurrently from multiple threads. + * + * @author Valentin Zickner + */ +public interface MailClientProvider { + + /** + * Returns the mail client for the given tenant identifier. + * + * @param tenantId the tenant identifier, or {@code null} for the default (non-tenant) case + * @return the mail client, or {@code null} if this provider cannot resolve one + */ + FlowableMailClient getMailClient(String tenantId); +} From c6776e8c1a233953cb1fca1f70e389ab5edae657 Mon Sep 17 00:00:00 2001 From: Valentin Zickner Date: Fri, 20 Mar 2026 06:11:36 +0100 Subject: [PATCH 2/5] fix review findings --- .../cmmn/engine/CmmnEngineConfiguration.java | 33 ++++++++++++++--- .../impl/mail/CmmnMailActivityDelegate.java | 17 +-------- .../cmmn/test/task/CmmnEmailTestCase.java | 2 +- .../cfg/mail/DefaultMailClientProvider.java | 3 +- .../engine/ProcessEngineConfiguration.java | 35 ++++++++++++++++--- .../bpmn/mail/BpmnMailActivityDelegate.java | 17 +-------- .../engine/test/bpmn/mail/EmailTestCase.java | 5 +++ .../common/api/client/MailClientProvider.java | 3 +- 8 files changed, 70 insertions(+), 45 deletions(-) diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java index 01fe8c3a956..0e0d9d8a24c 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java @@ -4095,16 +4095,24 @@ public CmmnEngineConfiguration setMailClientProvider(MailClientProvider mailClie return this; } + /** + * @deprecated use {@link #getMailClientProvider()} and {@link MailClientProvider#getMailClient(String)} with tenantId {@code null} instead + */ + @Deprecated public FlowableMailClient getDefaultMailClient() { - if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { - return defaultProvider.getDefaultMailClient(); - } - return null; + return mailClientProvider.getMailClient(null); } + /** + * @deprecated use {@link #setMailClientProvider(MailClientProvider)} instead + */ + @Deprecated public CmmnEngineConfiguration setDefaultMailClient(FlowableMailClient defaultMailClient) { if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { defaultProvider.setDefaultMailClient(defaultMailClient); + } else { + throw new FlowableException("The mail client provider is not an instance of DefaultMailClientProvider. " + + "Use setMailClientProvider instead."); } return this; } @@ -4241,20 +4249,35 @@ public MailServerInfo getMailServer(String tenantId) { return mailServers.get(tenantId); } + /** + * @deprecated use {@link #getMailClientProvider()} instead + */ + @Deprecated public Map getMailClients() { if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { return defaultProvider.getMailClients(); } - return new HashMap<>(); + return Collections.emptyMap(); } + /** + * @deprecated use {@link #setMailClientProvider(MailClientProvider)} instead + */ + @Deprecated public CmmnEngineConfiguration setMailClients(Map mailClients) { if (this.mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { defaultProvider.getMailClients().putAll(mailClients); + } else { + throw new FlowableException("The mail client provider is not an instance of DefaultMailClientProvider. " + + "Use setMailClientProvider instead."); } return this; } + /** + * @deprecated use {@link #getMailClientProvider().getMailClient(String)} instead + */ + @Deprecated public FlowableMailClient getMailClient(String tenantId) { return mailClientProvider.getMailClient(tenantId); } diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java index 97d109eedc7..5b223d3071d 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/mail/CmmnMailActivityDelegate.java @@ -12,7 +12,6 @@ */ package org.flowable.cmmn.engine.impl.behavior.impl.mail; -import org.apache.commons.lang3.StringUtils; import org.flowable.cmmn.api.delegate.DelegatePlanItemInstance; import org.flowable.cmmn.api.delegate.PlanItemJavaDelegate; import org.flowable.cmmn.engine.CmmnEngineConfiguration; @@ -21,7 +20,6 @@ import org.flowable.common.engine.impl.mail.BaseMailActivityDelegate; import org.flowable.content.api.ContentService; import org.flowable.mail.common.api.client.FlowableMailClient; -import org.flowable.mail.common.api.client.MailClientProvider; /** * @author Filip Hrisafov @@ -36,20 +34,7 @@ public void execute(DelegatePlanItemInstance planItemInstance) { @Override protected FlowableMailClient getMailClient(DelegatePlanItemInstance planItemInstance) { CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(); - String tenantId = planItemInstance.getTenantId(); - FlowableMailClient mailClient = null; - - MailClientProvider mailClientProvider = cmmnEngineConfiguration.getMailClientProvider(); - if (mailClientProvider != null) { - if (StringUtils.isNotBlank(tenantId)) { - mailClient = mailClientProvider.getMailClient(tenantId); - } - if (mailClient == null) { - mailClient = mailClientProvider.getMailClient(null); - } - } - - return mailClient; + return cmmnEngineConfiguration.getMailClientProvider().getMailClient(planItemInstance.getTenantId()); } @Override diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java index e5d33628fb8..71564d9feff 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java @@ -62,12 +62,12 @@ public void setUp() { @AfterEach public void tearDown() { - cmmnEngineConfiguration.setMailClientProvider(initialMailClientProvider); if (initialMailServers != null) { cmmnEngineConfiguration.getMailServers().clear(); cmmnEngineConfiguration.getMailServers().putAll(initialMailServers); } reinitializeMailClients(); + cmmnEngineConfiguration.setMailClientProvider(initialMailClientProvider); } @AfterAll diff --git a/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java index ce78b8f5355..ff86a0577f8 100644 --- a/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java +++ b/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/mail/DefaultMailClientProvider.java @@ -15,6 +15,7 @@ import java.util.HashMap; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.flowable.mail.common.api.client.FlowableMailClient; import org.flowable.mail.common.api.client.MailClientProvider; @@ -35,7 +36,7 @@ public DefaultMailClientProvider() { @Override public FlowableMailClient getMailClient(String tenantId) { - if (tenantId != null) { + if (StringUtils.isNotBlank(tenantId)) { FlowableMailClient client = tenantMailClients.get(tenantId); if (client != null) { return client; diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java b/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java index c335b84ea5d..d11c7fe355a 100755 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/ProcessEngineConfiguration.java @@ -16,11 +16,13 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.time.Duration; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.sql.DataSource; +import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.async.AsyncTaskExecutor; import org.flowable.common.engine.api.async.AsyncTaskInvoker; import org.flowable.common.engine.impl.AbstractBuildableEngineConfiguration; @@ -255,16 +257,24 @@ public ProcessEngineConfiguration setMailClientProvider(MailClientProvider mailC return this; } + /** + * @deprecated use {@link #getMailClientProvider()} and {@link MailClientProvider#getMailClient(String)} with {@code null} instead + */ + @Deprecated public FlowableMailClient getDefaultMailClient() { - if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { - return defaultProvider.getDefaultMailClient(); - } - return null; + return mailClientProvider.getMailClient(null); } + /** + * @deprecated use {@link #setMailClientProvider(MailClientProvider)} instead + */ + @Deprecated public ProcessEngineConfiguration setDefaultMailClient(FlowableMailClient defaultMailClient) { if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { defaultProvider.setDefaultMailClient(defaultMailClient); + } else { + throw new FlowableException("The mail client provider is not an instance of DefaultMailClientProvider. " + + "Use setMailClientProvider instead."); } return this; } @@ -401,20 +411,35 @@ public ProcessEngineConfiguration setMailServers(Map mai return this; } + /** + * @deprecated use {@link #getMailClientProvider().getMailClient(String)} instead + */ + @Deprecated public FlowableMailClient getMailClient(String tenantId) { return mailClientProvider.getMailClient(tenantId); } + /** + * @deprecated use {@link #getMailClientProvider()} instead + */ + @Deprecated public Map getMailClients() { if (mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { return defaultProvider.getMailClients(); } - return new HashMap<>(); + return Collections.emptyMap(); } + /** + * @deprecated use {@link #setMailClientProvider(MailClientProvider)} instead + */ + @Deprecated public ProcessEngineConfiguration setMailClients(Map mailClients) { if (this.mailClientProvider instanceof DefaultMailClientProvider defaultProvider) { defaultProvider.getMailClients().putAll(mailClients); + } else { + throw new FlowableException("The mail client provider is not an instance of DefaultMailClientProvider. " + + "Use setMailClientProvider instead."); } return this; } diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java index 61e50985ed3..f358322a417 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/mail/BpmnMailActivityDelegate.java @@ -12,7 +12,6 @@ */ package org.flowable.engine.impl.bpmn.mail; -import org.apache.commons.lang3.StringUtils; import org.flowable.common.engine.api.delegate.Expression; import org.flowable.common.engine.impl.mail.BaseMailActivityDelegate; import org.flowable.content.api.ContentService; @@ -21,7 +20,6 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.mail.common.api.client.FlowableMailClient; -import org.flowable.mail.common.api.client.MailClientProvider; /** * @author Filip Hrisafov @@ -37,20 +35,7 @@ public void execute(DelegateExecution execution) { @Override protected FlowableMailClient getMailClient(DelegateExecution execution) { ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(); - String tenantId = execution.getTenantId(); - FlowableMailClient mailClient = null; - - MailClientProvider mailClientProvider = processEngineConfiguration.getMailClientProvider(); - if (mailClientProvider != null) { - if (StringUtils.isNotBlank(tenantId)) { - mailClient = mailClientProvider.getMailClient(tenantId); - } - if (mailClient == null) { - mailClient = mailClientProvider.getMailClient(null); - } - } - - return mailClient; + return processEngineConfiguration.getMailClientProvider().getMailClient(execution.getTenantId()); } @Override diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java index 8c49f175ed8..05022512e1c 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java @@ -18,6 +18,7 @@ import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; import org.flowable.engine.impl.test.PluggableFlowableTestCase; +import org.flowable.mail.common.api.client.MailClientProvider; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; @@ -31,12 +32,14 @@ public abstract class EmailTestCase extends PluggableFlowableTestCase { protected Wiser wiser; private String initialForceTo; + private MailClientProvider initialMailClientProvider; private Map initialMailServers; @BeforeEach protected void setUp() throws Exception { initialForceTo = processEngineConfiguration.getMailServerForceTo(); + initialMailClientProvider = processEngineConfiguration.getMailClientProvider(); Map mailServers = processEngineConfiguration.getMailServers(); initialMailServers = mailServers == null ? null : new HashMap<>(mailServers); boolean serverUpAndRunning = false; @@ -64,11 +67,13 @@ protected void tearDown() throws Exception { processEngineConfiguration.setMailServerForceTo(initialForceTo); processEngineConfiguration.setMailServers(initialMailServers); reinitilizeMailClients(); + processEngineConfiguration.setMailClientProvider(initialMailClientProvider); } protected void reinitilizeMailClients() { processEngineConfiguration.setDefaultMailClient(null); processEngineConfiguration.getMailClients().clear(); + processEngineConfiguration.setMailClientProvider(null); processEngineConfiguration.initMailClients(); } diff --git a/modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java b/modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java index f0d26f00c4e..e504c9add92 100644 --- a/modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java +++ b/modules/flowable-mail/src/main/java/org/flowable/mail/common/api/client/MailClientProvider.java @@ -22,13 +22,14 @@ * * @author Valentin Zickner */ +@FunctionalInterface public interface MailClientProvider { /** * Returns the mail client for the given tenant identifier. * * @param tenantId the tenant identifier, or {@code null} for the default (non-tenant) case - * @return the mail client, or {@code null} if this provider cannot resolve one + * @return the mail client for the given tenant */ FlowableMailClient getMailClient(String tenantId); } From aba3b83ef014732269b41a90e240f1edc5e886a2 Mon Sep 17 00:00:00 2001 From: Valentin Zickner Date: Fri, 20 Mar 2026 07:55:05 +0100 Subject: [PATCH 3/5] fix mail provider set/reset structure --- .../org/flowable/cmmn/test/task/CmmnEmailTestCase.java | 4 +--- .../test/task/CmmnMailTaskWithMailClientProviderTest.java | 5 +++-- .../bpmn/mail/EmailSendTaskWithMailClientProviderTest.java | 7 ++++--- .../org/flowable/engine/test/bpmn/mail/EmailTestCase.java | 4 +--- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java index 71564d9feff..223dd8d5c5f 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnEmailTestCase.java @@ -56,6 +56,7 @@ public static void setupWiser() throws Exception { public void setUp() { wiser.getMessages().clear(); initialMailClientProvider = cmmnEngineConfiguration.getMailClientProvider(); + reinitializeMailClients(); Map mailServers = cmmnEngineConfiguration.getMailServers(); initialMailServers = mailServers == null ? null : new HashMap<>(mailServers); } @@ -66,7 +67,6 @@ public void tearDown() { cmmnEngineConfiguration.getMailServers().clear(); cmmnEngineConfiguration.getMailServers().putAll(initialMailServers); } - reinitializeMailClients(); cmmnEngineConfiguration.setMailClientProvider(initialMailClientProvider); } @@ -76,8 +76,6 @@ public static void stopWiser() { } protected void reinitializeMailClients() { - cmmnEngineConfiguration.setDefaultMailClient(null); - cmmnEngineConfiguration.getMailClients().clear(); cmmnEngineConfiguration.setMailClientProvider(null); cmmnEngineConfiguration.initMailClients(); } diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java index a787872c4fa..9e359d9a3bf 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java @@ -16,6 +16,7 @@ import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.flowable.cmmn.engine.test.CmmnDeployment; import org.flowable.common.engine.impl.cfg.mail.FlowableMailClientCreator; import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; @@ -36,10 +37,10 @@ public class CmmnMailTaskWithMailClientProviderTest extends CmmnEmailTestCase { @Test @CmmnDeployment(resources = CMMN_RESOURCE) - public void testProviderReturnsClientForNullTenantId() { + public void testProviderReturnsClientForEmptyTenantId() { FlowableMailClient providerClient = createMailClient("provider-default@flowable.org"); cmmnEngineConfiguration.setMailClientProvider(requestedTenantId -> { - if (requestedTenantId == null) { + if (StringUtils.isEmpty(requestedTenantId)) { return providerClient; } return null; diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java index fb67e10b2e5..3c01e757a22 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java @@ -16,6 +16,7 @@ import java.util.List; +import org.drools.util.StringUtils; import org.flowable.common.engine.impl.cfg.mail.FlowableMailClientCreator; import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; import org.flowable.engine.test.Deployment; @@ -39,12 +40,12 @@ public class EmailSendTaskWithMailClientProviderTest extends EmailTestCase { @BeforeEach void saveProvider() { initialMailClientProvider = processEngineConfiguration.getMailClientProvider(); + reinitilizeMailClients(); } @AfterEach void restoreProvider() { processEngineConfiguration.setMailClientProvider(initialMailClientProvider); - reinitilizeMailClients(); } @Test @@ -101,10 +102,10 @@ public void testDefaultProviderResolvesTenantFromStaticConfig() throws Exception @Test @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") - public void testProviderReturnsClientForNullTenantId() throws Exception { + public void testProviderReturnsClientForEmptyTenantId() throws Exception { FlowableMailClient defaultProviderClient = createMailClient("provider-default@flowable.org"); processEngineConfiguration.setMailClientProvider(requestedTenantId -> { - if (requestedTenantId == null) { + if (StringUtils.isEmpty(requestedTenantId)) { return defaultProviderClient; } return null; diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java index 05022512e1c..fdb8aac573c 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailTestCase.java @@ -40,6 +40,7 @@ protected void setUp() throws Exception { initialForceTo = processEngineConfiguration.getMailServerForceTo(); initialMailClientProvider = processEngineConfiguration.getMailClientProvider(); + reinitilizeMailClients(); Map mailServers = processEngineConfiguration.getMailServers(); initialMailServers = mailServers == null ? null : new HashMap<>(mailServers); boolean serverUpAndRunning = false; @@ -66,13 +67,10 @@ protected void tearDown() throws Exception { processEngineConfiguration.setMailServerForceTo(initialForceTo); processEngineConfiguration.setMailServers(initialMailServers); - reinitilizeMailClients(); processEngineConfiguration.setMailClientProvider(initialMailClientProvider); } protected void reinitilizeMailClients() { - processEngineConfiguration.setDefaultMailClient(null); - processEngineConfiguration.getMailClients().clear(); processEngineConfiguration.setMailClientProvider(null); processEngineConfiguration.initMailClients(); } From 15f6e21c9757c1c7356a46b7930185d2313871b0 Mon Sep 17 00:00:00 2001 From: Valentin Zickner Date: Fri, 20 Mar 2026 08:45:21 +0100 Subject: [PATCH 4/5] improve CMMN static tenant test --- ...mmnMailTaskWithMailClientProviderTest.java | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java index 9e359d9a3bf..33ee815525e 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java @@ -101,29 +101,19 @@ public void testDefaultProviderFallsBackToDefaultClient() { } @Test + @CmmnDeployment(resources = CMMN_RESOURCE, tenantId = "staticTenant") public void testDefaultProviderResolvesTenantFromStaticConfig() { - String tenantId = "staticTenant"; - addMailServer(tenantId, "static-tenant@flowable.org", null); + addMailServer("staticTenant", "static-tenant@flowable.org", null); reinitializeMailClients(); - String deploymentId = cmmnRepositoryService.createDeployment() - .addClasspathResource(CMMN_RESOURCE) - .tenantId(tenantId) - .deploy() - .getId(); - - try { - cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("testSimpleTextMail") - .tenantId(tenantId) - .start(); + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("testSimpleTextMail") + .tenantId("staticTenant") + .start(); - List messages = wiser.getMessages(); - assertThat(messages).hasSize(1); - assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("static-tenant@flowable.org"); - } finally { - cmmnRepositoryService.deleteDeployment(deploymentId, true); - } + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("static-tenant@flowable.org"); } @Test From 558b14e909dadcf73a0bf912b5c4488e0917c4ab Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Fri, 20 Mar 2026 14:47:33 +0100 Subject: [PATCH 5/5] polish --- ...mmnMailTaskWithMailClientProviderTest.java | 48 ++++++-------- ...ailSendTaskWithMailClientProviderTest.java | 63 +++++++------------ 2 files changed, 39 insertions(+), 72 deletions(-) diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java index 33ee815525e..c534f493d36 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.java @@ -18,9 +18,9 @@ import org.apache.commons.lang3.StringUtils; import org.flowable.cmmn.engine.test.CmmnDeployment; +import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; import org.flowable.common.engine.impl.cfg.mail.FlowableMailClientCreator; import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; -import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; import org.flowable.mail.common.api.client.FlowableMailClient; import org.flowable.mail.common.api.client.MailClientProvider; import org.junit.jupiter.api.Test; @@ -31,13 +31,11 @@ * * @author Valentin Zickner */ -public class CmmnMailTaskWithMailClientProviderTest extends CmmnEmailTestCase { - - private static final String CMMN_RESOURCE = "org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn"; +class CmmnMailTaskWithMailClientProviderTest extends CmmnEmailTestCase { @Test - @CmmnDeployment(resources = CMMN_RESOURCE) - public void testProviderReturnsClientForEmptyTenantId() { + @CmmnDeployment(resources = "org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn") + void testProviderReturnsClientForEmptyTenantId() { FlowableMailClient providerClient = createMailClient("provider-default@flowable.org"); cmmnEngineConfiguration.setMailClientProvider(requestedTenantId -> { if (StringUtils.isEmpty(requestedTenantId)) { @@ -56,39 +54,29 @@ public void testProviderReturnsClientForEmptyTenantId() { } @Test - public void testProviderReturnsClientForTenant() { - String tenantId = "providerTenant"; + @CmmnDeployment(resources = "org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn", tenantId = "providerTenant") + void testProviderReturnsClientForTenant() { FlowableMailClient tenantClient = createMailClient("provider-tenant@flowable.org"); cmmnEngineConfiguration.setMailClientProvider(requestedTenantId -> { - if (tenantId.equals(requestedTenantId)) { + if ("providerTenant".equals(requestedTenantId)) { return tenantClient; } return null; }); - String deploymentId = cmmnRepositoryService.createDeployment() - .addClasspathResource(CMMN_RESOURCE) - .tenantId(tenantId) - .deploy() - .getId(); - - try { - cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("testSimpleTextMail") - .tenantId(tenantId) - .start(); - - List messages = wiser.getMessages(); - assertThat(messages).hasSize(1); - assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-tenant@flowable.org"); - } finally { - cmmnRepositoryService.deleteDeployment(deploymentId, true); - } + cmmnRuntimeService.createCaseInstanceBuilder() + .caseDefinitionKey("testSimpleTextMail") + .tenantId("providerTenant") + .start(); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-tenant@flowable.org"); } @Test - @CmmnDeployment(resources = CMMN_RESOURCE) + @CmmnDeployment(resources = "org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn") public void testDefaultProviderFallsBackToDefaultClient() { cmmnRuntimeService.createCaseInstanceBuilder() .caseDefinitionKey("testSimpleTextMail") @@ -101,7 +89,7 @@ public void testDefaultProviderFallsBackToDefaultClient() { } @Test - @CmmnDeployment(resources = CMMN_RESOURCE, tenantId = "staticTenant") + @CmmnDeployment(resources = "org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn", tenantId = "staticTenant") public void testDefaultProviderResolvesTenantFromStaticConfig() { addMailServer("staticTenant", "static-tenant@flowable.org", null); reinitializeMailClients(); @@ -117,7 +105,7 @@ public void testDefaultProviderResolvesTenantFromStaticConfig() { } @Test - @CmmnDeployment(resources = CMMN_RESOURCE) + @CmmnDeployment(resources = "org/flowable/cmmn/test/task/CmmnMailTaskWithMailClientProviderTest.testSimpleTextMail.cmmn") public void testDefaultMailClientProviderIsSetByDefault() { assertThat(cmmnEngineConfiguration.getMailClientProvider()).isInstanceOf(DefaultMailClientProvider.class); diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java index 3c01e757a22..53d9bf5aead 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/bpmn/mail/EmailSendTaskWithMailClientProviderTest.java @@ -17,10 +17,10 @@ import java.util.List; import org.drools.util.StringUtils; +import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; import org.flowable.common.engine.impl.cfg.mail.FlowableMailClientCreator; import org.flowable.common.engine.impl.cfg.mail.MailServerInfo; import org.flowable.engine.test.Deployment; -import org.flowable.common.engine.impl.cfg.mail.DefaultMailClientProvider; import org.flowable.mail.common.api.client.FlowableMailClient; import org.flowable.mail.common.api.client.MailClientProvider; import org.junit.jupiter.api.AfterEach; @@ -33,7 +33,7 @@ * * @author Valentin Zickner */ -public class EmailSendTaskWithMailClientProviderTest extends EmailTestCase { +class EmailSendTaskWithMailClientProviderTest extends EmailTestCase { protected MailClientProvider initialMailClientProvider; @@ -49,60 +49,39 @@ void restoreProvider() { } @Test - public void testProviderReturnsClientForTenant() throws Exception { - String tenantId = "providerTenant"; - + @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml", tenantId = "providerTenant") + void testProviderReturnsClientForTenant() { FlowableMailClient tenantClient = createMailClient("provider-tenant@flowable.org"); processEngineConfiguration.setMailClientProvider(requestedTenantId -> { - if (tenantId.equals(requestedTenantId)) { + if ("providerTenant".equals(requestedTenantId)) { return tenantClient; } return null; }); - String deploymentId = repositoryService.createDeployment() - .addClasspathResource("org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") - .tenantId(tenantId) - .deploy() - .getId(); - - try { - runtimeService.startProcessInstanceByKeyAndTenantId("simpleTextOnly", tenantId); - - List messages = wiser.getMessages(); - assertThat(messages).hasSize(1); - assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-tenant@flowable.org"); - } finally { - deleteDeployment(deploymentId); - } + runtimeService.startProcessInstanceByKeyAndTenantId("simpleTextOnly", "providerTenant"); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("provider-tenant@flowable.org"); } @Test - public void testDefaultProviderResolvesTenantFromStaticConfig() throws Exception { - String tenantId = "staticTenant"; - addMailServer(tenantId, "static-tenant@flowable.org", null); + @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml", tenantId = "staticTenant") + void testDefaultProviderResolvesTenantFromStaticConfig() { + addMailServer("staticTenant", "static-tenant@flowable.org", null); reinitilizeMailClients(); - String deploymentId = repositoryService.createDeployment() - .addClasspathResource("org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") - .tenantId(tenantId) - .deploy() - .getId(); - - try { - runtimeService.startProcessInstanceByKeyAndTenantId("simpleTextOnly", tenantId); - - List messages = wiser.getMessages(); - assertThat(messages).hasSize(1); - assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("static-tenant@flowable.org"); - } finally { - deleteDeployment(deploymentId); - } + runtimeService.startProcessInstanceByKeyAndTenantId("simpleTextOnly", "staticTenant"); + + List messages = wiser.getMessages(); + assertThat(messages).hasSize(1); + assertThat(messages.get(0).getEnvelopeSender()).isEqualTo("static-tenant@flowable.org"); } @Test @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") - public void testProviderReturnsClientForEmptyTenantId() throws Exception { + void testProviderReturnsClientForEmptyTenantId() { FlowableMailClient defaultProviderClient = createMailClient("provider-default@flowable.org"); processEngineConfiguration.setMailClientProvider(requestedTenantId -> { if (StringUtils.isEmpty(requestedTenantId)) { @@ -120,7 +99,7 @@ public void testProviderReturnsClientForEmptyTenantId() throws Exception { @Test @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") - public void testDefaultProviderFallsBackToDefaultClient() throws Exception { + void testDefaultProviderFallsBackToDefaultClient() { runtimeService.startProcessInstanceByKey("simpleTextOnly"); List messages = wiser.getMessages(); @@ -131,7 +110,7 @@ public void testDefaultProviderFallsBackToDefaultClient() throws Exception { @Test @Deployment(resources = "org/flowable/engine/test/bpmn/mail/EmailSendTaskTest.testSimpleTextMail.bpmn20.xml") - public void testDefaultMailClientProviderIsSetByDefault() throws Exception { + void testDefaultMailClientProviderIsSetByDefault() { assertThat(processEngineConfiguration.getMailClientProvider()).isInstanceOf(DefaultMailClientProvider.class); runtimeService.startProcessInstanceByKey("simpleTextOnly");