From b63aadfa2009c4f4a628fe1c06ef79fb2f4389a3 Mon Sep 17 00:00:00 2001 From: Stefan Bechtold Date: Thu, 5 Mar 2026 11:22:30 +0100 Subject: [PATCH 01/13] increase version for next increment --- .../bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevbackoffice/external-dependencies.xml | 2 +- .../bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevenvconfig/external-dependencies.xml | 2 +- .../hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml | 2 +- .../bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml | 2 +- .../bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevreporting/external-dependencies.xml | 2 +- .../hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevtoolkit/external-dependencies.xml | 2 +- sonar-project.properties | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml index 2a35569..c72b659 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml @@ -1,6 +1,6 @@ - + diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml index b86b779..fa2b633 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevbackoffice - 5.0.1 + 5.0.2-snapshot jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml index 116068c..1a60adb 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml @@ -1,7 +1,7 @@ + name="cxdevenvconfig" version="5.0.2-snapshot" usemaven="true"> diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml index e3c9db1..40b66b5 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevenvconfig - 5.0.1 + 5.0.2-snapshot jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml index f663b49..d82b9b4 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml @@ -1,6 +1,6 @@ - + diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml index 82f7db5..b2d98f9 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevproxy - 5.0.1 + 5.0.2-snapshot jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml index a0b8b68..fceb231 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml @@ -1,6 +1,6 @@ - + diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml index c5261aa..deb03f4 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevreporting - 5.0.1 + 5.0.2-snapshot jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml index aaa5c53..846cc5d 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml @@ -1,7 +1,7 @@ + name="cxdevtoolkit" version="5.0.2-snapshot" usemaven="true"> diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml index 72e225e..1c46302 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevtoolkit - 5.0.1 + 5.0.2-snapshot jar diff --git a/sonar-project.properties b/sonar-project.properties index 635b425..72f3a76 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.organization=cxdevtools # This is the name and version displayed in the SonarCloud UI. sonar.projectName=cxdevtools-workspace -sonar.projectVersion=5.0.1 +sonar.projectVersion=5.0.2-snapshot # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. sonar.sources=core-customize/hybris/bin/custom/cxdevtools From 365e7555d8060303c54767fdc3e84d285e895684 Mon Sep 17 00:00:00 2001 From: Stefan Bechtold Date: Fri, 6 Mar 2026 09:35:49 +0100 Subject: [PATCH 02/13] add debug messages to build script --- core-customize/build.gradle.kts | 40 ++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/core-customize/build.gradle.kts b/core-customize/build.gradle.kts index c264117..42740f5 100644 --- a/core-customize/build.gradle.kts +++ b/core-customize/build.gradle.kts @@ -118,13 +118,47 @@ if (project.hasProperty("CXDEV_ARTEFACT_BASEURL") && project.hasProperty("CXDEV_ val COMMERCE_VERSION = CCV2.manifest.effectiveVersion tasks.register("downloadPlatform") { - src(BASEURL + "/commerce/hybris-commerce-suite-${COMMERCE_VERSION}.zip") - dest(file("${dependencyDir}/hybris-commerce-suite-${COMMERCE_VERSION}.zip")) - header("Authorization", "Basic ${AUTHORIZATION}") + val targetFile = file("${dependencyDir}/hybris-commerce-suite-${COMMERCE_VERSION}.zip") + + src("$BASEURL/commerce/hybris-commerce-suite-${COMMERCE_VERSION}.zip") + dest(targetFile) + + header("Authorization", "Basic $AUTHORIZATION") + overwrite(false) tempAndMove(true) onlyIfModified(true) useETag(true) + + doFirst { + logger.lifecycle("=== Download Platform Debug ===") + logger.lifecycle("Source URL: $BASEURL/commerce/hybris-commerce-suite-${COMMERCE_VERSION}.zip") + logger.lifecycle("Destination: ${targetFile.absolutePath}") + logger.lifecycle("Destination exists: ${targetFile.exists()}") + logger.lifecycle("Dependency dir: ${file(dependencyDir).absolutePath}") + + if (file(dependencyDir).exists()) { + logger.lifecycle("Directory content:") + file(dependencyDir).listFiles()?.forEach { + logger.lifecycle(" - ${it.name}") + } + } + } + + doLast { + logger.lifecycle("=== Download completed ===") + logger.lifecycle("File exists after download: ${targetFile.exists()}") + logger.lifecycle("File size: ${targetFile.length()}") + + logger.lifecycle("Dependency dir: ${file(dependencyDir).absolutePath}") + + if (file(dependencyDir).exists()) { + logger.lifecycle("Directory content:") + file(dependencyDir).listFiles()?.forEach { + logger.lifecycle(" - ${it.name}") + } + } + } } tasks.named("bootstrapPlatform") { From e438bd4b264155dbd76ecee92cca480db4bcb910 Mon Sep 17 00:00:00 2001 From: Stefan Bechtold Date: Tue, 10 Mar 2026 23:49:06 +0100 Subject: [PATCH 03/13] add ImpEx localization helper for enhanced processing of sample data --- .../impex/ImpexLocalizationHelper.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/impex/ImpexLocalizationHelper.java diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/impex/ImpexLocalizationHelper.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/impex/ImpexLocalizationHelper.java new file mode 100644 index 0000000..cf43ef0 --- /dev/null +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/impex/ImpexLocalizationHelper.java @@ -0,0 +1,60 @@ +package me.cxdev.commerce.toolkit.impex; + +import java.util.Arrays; +import java.util.HashMap; + +import de.hybris.platform.servicelayer.i18n.util.LanguageUtils; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ImpexLocalizationHelper { + private static final Logger LOG = LoggerFactory.getLogger(ImpexLocalizationHelper.class); + + public static boolean languageSupported(final String isocode) { + return LanguageUtils.isLanguagePresent(isocode); + } + + public static boolean languageSupported(final String isocode, String languages) { + if (StringUtils.isBlank(languages)) { + return false; + } + + boolean isContainedInList = Arrays.stream(StringUtils.split(languages, ",")) + .map(StringUtils::trimToEmpty) + .anyMatch(isocode::equalsIgnoreCase); + return isContainedInList && languageSupported(isocode); + } + + public static void filterUnlocalizedLine(HashMap valueLine, Integer column) { + if (isLocalizedLine(valueLine, column)) { + valueLine.clear(); + } + } + + public static void filterUnlocalizedOrPrimaryLine(HashMap valueLine, Integer column, String isocode) { + if (isLocalizedLine(valueLine, column) && !hasCorrectLocale(valueLine, column, isocode)) { + valueLine.clear(); + } + } + + public static void filterLocalizedLine(HashMap valueLine, Integer column, String isocode) { + if (isUnlocalizedLine(valueLine, column) || !hasCorrectLocale(valueLine, column, isocode)) { + valueLine.clear(); + } + } + + public static boolean isLocalizedLine(HashMap valueLine, Integer column) { + return StringUtils.isNotBlank(valueLine.get(column)); + } + + public static boolean isUnlocalizedLine(HashMap valueLine, Integer column) { + return !isLocalizedLine(valueLine, column); + } + + public static boolean hasCorrectLocale(HashMap valueLine, Integer column, String isocode) { + return (StringUtils.isBlank(isocode) && StringUtils.isBlank(valueLine.get(column))) + || StringUtils.equalsIgnoreCase(valueLine.get(column), isocode); + } +} From 592673764c5e457262338818fb0d5644f967f132 Mon Sep 17 00:00:00 2001 From: Stefan Bechtold Date: Fri, 27 Mar 2026 13:32:29 +0100 Subject: [PATCH 04/13] switch default configuration to use SSL --- .../cxdevtools/cxdevproxy/project.properties | 7 ++-- .../resources/cxdevproxy-spring.xml | 1 - .../proxy/livecycle/UndertowProxyManager.java | 34 +++++++------------ 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/project.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/project.properties index 58b6d81..8a04e3b 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/project.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/project.properties @@ -9,15 +9,14 @@ cxdevproxy.enabled=false # SSL / Keystore Configuration # Defines the keystore details used for securing the proxy server via HTTPS. -cxdevproxy.ssl.enabled=false +cxdevproxy.ssl.enabled=true cxdevproxy.ssl.keystore.path=${HYBRIS_CONFIG_DIR}/../../../certificates/local.cxdev.me.p12 cxdevproxy.ssl.keystore.password=123456 cxdevproxy.ssl.keystore.alias=local.cxdev.me # Undertow Server Binding # Defines the network interface, hostname, and port the embedded proxy will listen on. -cxdevproxy.server.bindaddress=127.0.0.1 -cxdevproxy.server.protocol=http +cxdevproxy.server.bindaddress=0.0.0.0 cxdevproxy.server.hostname=local.cxdev.me cxdevproxy.server.port=8080 @@ -38,7 +37,7 @@ cxdevproxy.proxy.ui.messages.codeasfallback=true # CX Dev Proxy - Frontend Routing (Target) # ----------------------------------------------------------------------- # Target configuration for routing frontend requests (e.g., local Angular dev server). -cxdevproxy.proxy.frontend.protocol=https +cxdevproxy.proxy.frontend.protocol=http cxdevproxy.proxy.frontend.hostname=localhost cxdevproxy.proxy.frontend.port=4200 diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy-spring.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy-spring.xml index 2abc298..974e8b9 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy-spring.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy-spring.xml @@ -10,7 +10,6 @@ - diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java index 22af03d..11b3261 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java @@ -62,28 +62,28 @@ public class UndertowProxyManager implements SmartLifecycle, InitializingBean, D private static final Logger LOG = LoggerFactory.getLogger(UndertowProxyManager.class); // Spring Injected Properties - private boolean enabled; + private boolean enabled = false; // SSL Properties - private boolean sslEnabled; + private boolean sslEnabled = true; private String sslKeystorePath; private String sslKeystorePassword; private String sslKeystoreAlias; // Server Binding Properties - private String serverBindAddress; - private String serverHostname; - private String serverProtocol; - private int serverPort; + private String serverBindAddress = "0.0.0.0"; + private String serverHostname = "localhost"; + private String serverProtocol = "https"; + private int serverPort = 8080; // Proxy Target Properties - private String frontendProtocol; - private String frontendHostname; - private int frontendPort; + private String frontendProtocol = "http"; + private String frontendHostname = "localhost"; + private int frontendPort = 4200; private String frontendRulesFilePath; - private String backendProtocol; - private String backendHostname; - private int backendPort; + private String backendProtocol = "https"; + private String backendHostname = "localhost"; + private int backendPort = 9002; private String backendRulesFilePath; private String backendContexts; @@ -198,11 +198,7 @@ public void start() { return; } - if (!sslEnabled) { - this.serverProtocol = "http"; - LOG.info("SSL is disabled. Forcing server protocol to 'http'."); - } - + this.serverProtocol = sslEnabled ? "https" : "http"; LOG.info("Starting embedded Undertow proxy (Protocol: {})...", this.serverProtocol); try { @@ -452,10 +448,6 @@ public void setServerHostname(String serverHostname) { this.serverHostname = serverHostname; } - public void setServerProtocol(String serverProtocol) { - this.serverProtocol = serverProtocol; - } - public void setServerPort(int serverPort) { this.serverPort = serverPort; } From ad8c8f61cb9e215a4748163096bb018f6dec8f73 Mon Sep 17 00:00:00 2001 From: Stefan Bechtold Date: Fri, 27 Mar 2026 13:34:34 +0100 Subject: [PATCH 05/13] make use of undertows handling of xforward headers --- .../config/cxdevproxy-interceptor-spring.xml | 7 ------- .../rulesets/cxdevproxy-backend-rules.groovy | 6 +----- .../rulesets/cxdevproxy-frontend-rules.groovy | 4 +--- .../proxy/livecycle/UndertowProxyManager.java | 17 +++++++++++++---- .../livecycle/GroovyRuleEngineServiceTest.java | 4 +--- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/config/cxdevproxy-interceptor-spring.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/config/cxdevproxy-interceptor-spring.xml index 9b03cf7..071694e 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/config/cxdevproxy-interceptor-spring.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/config/cxdevproxy-interceptor-spring.xml @@ -2,13 +2,6 @@ - - - - - - - diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-backend-rules.groovy b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-backend-rules.groovy index 8235f6c..aa7f907 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-backend-rules.groovy +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-backend-rules.groovy @@ -1,5 +1 @@ -return [ - interceptor() - .constrainedBy( isMethod("GET"), pathMatches("/**/carts/current") ) - .perform( jsonResponse('{"type": "cartWsDTO", "totalItems": 5}') ) -] \ No newline at end of file +return [] \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-frontend-rules.groovy b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-frontend-rules.groovy index 43e25a7..aa7f907 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-frontend-rules.groovy +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/resources/cxdevproxy/rulesets/cxdevproxy-frontend-rules.groovy @@ -1,3 +1 @@ -def interceptor = [] -interceptor << forwardedHeaders -return interceptor \ No newline at end of file +return [] \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java index 11b3261..649eabf 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/src/me/cxdev/commerce/proxy/livecycle/UndertowProxyManager.java @@ -202,20 +202,29 @@ public void start() { LOG.info("Starting embedded Undertow proxy (Protocol: {})...", this.serverProtocol); try { + XnioSsl frontendSslContext = "https".equalsIgnoreCase(frontendProtocol) ? createTrustAllXnioSsl(frontendHostname) : null; String frontendUrl = frontendProtocol + "://" + frontendHostname + ":" + frontendPort; LoadBalancingProxyClient frontendClient = new LoadBalancingProxyClient() - .addHost(new URI(frontendUrl), createTrustAllXnioSsl(frontendHostname)) + .addHost(new URI(frontendUrl), frontendSslContext) .setConnectionsPerThread(20); + XnioSsl backendSslContext = "https".equalsIgnoreCase(backendProtocol) ? createTrustAllXnioSsl(backendHostname) : null; String backendUrl = backendProtocol + "://" + backendHostname + ":" + backendPort; LoadBalancingProxyClient backendClient = new LoadBalancingProxyClient() - .addHost(new URI(backendUrl), createTrustAllXnioSsl(backendHostname)) + .addHost(new URI(backendUrl), backendSslContext) .setConnectionsPerThread(20); - HttpHandler baseFrontendHandler = ProxyHandler.builder().setProxyClient(frontendClient).build(); + HttpHandler baseFrontendHandler = ProxyHandler.builder() + .setProxyClient(frontendClient) + .setReuseXForwarded(true) + .build(); HttpHandler finalFrontendHandler = applyRules(frontendHandlersRef.get(), baseFrontendHandler); - HttpHandler baseBackendHandler = ProxyHandler.builder().setProxyClient(backendClient).setMaxRequestTime(30000).build(); + HttpHandler baseBackendHandler = ProxyHandler.builder() + .setProxyClient(backendClient) + .setMaxRequestTime(30000) + .setReuseXForwarded(true) + .build(); HttpHandler finalBackendHandler = applyRules(backendHandlersRef.get(), baseBackendHandler); List activeBackendContexts = determineBackendContexts(); diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/testsrc/me/cxdev/commerce/proxy/livecycle/GroovyRuleEngineServiceTest.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/testsrc/me/cxdev/commerce/proxy/livecycle/GroovyRuleEngineServiceTest.java index 7fb0c8c..d0c4b2d 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/testsrc/me/cxdev/commerce/proxy/livecycle/GroovyRuleEngineServiceTest.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/testsrc/me/cxdev/commerce/proxy/livecycle/GroovyRuleEngineServiceTest.java @@ -54,7 +54,6 @@ void setUp() { // Setup Spring ApplicationContext mocks with custom bean names to test the prefix stripping Map interceptors = new HashMap<>(); - interceptors.put("cxdevproxyInterceptorForwardedHeaders", mockInterceptor); interceptors.put("customInterceptorWithoutPrefix", mockInterceptor); // Edge case Map conditions = new HashMap<>(); @@ -129,8 +128,7 @@ void testEvaluateScript_WithValidScriptAndBindings(@TempDir Path tempDir) throws assertNotNull(result, "Result list should not be null"); assertEquals(2, result.size(), "Script should return exactly two interceptors"); - // Assert that the first returned interceptor is the exact mock instance we injected, - // proving that 'forwardedHeaders' was successfully bound to 'cxdevproxyInterceptorForwardedHeaders' + // Assert that the first returned interceptor is the exact mock instance we injected assertEquals(mockInterceptor, result.get(0)); } From a8a1db9e2866c4522d1ba4ce9e636271c84c8849 Mon Sep 17 00:00:00 2001 From: Ole Ruhl Date: Tue, 9 Jun 2026 14:54:46 +0200 Subject: [PATCH 06/13] feat: add ThymeleafEmailTemplate item type --- .../resources/cxdevtoolkit-items.xml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-items.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-items.xml index 8323df6..34168b1 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-items.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-items.xml @@ -13,5 +13,39 @@ + + + + + + + + + + + HYBRIS.LONG_STRING + + + TEXT + + + CLOB + + + TEXT + + + NCLOB + + + + + + + + + + + From 18df31d44b01edcd6a7637cf9c74a228545c4b63 Mon Sep 17 00:00:00 2001 From: Ole Ruhl Date: Tue, 9 Jun 2026 14:55:05 +0200 Subject: [PATCH 07/13] feat: add database-backed email template resolution via DAO and service --- .../resources/cxdevtoolkit-spring.xml | 11 ++++++ .../email/dao/EmailTemplateResolverDao.java | 9 +++++ .../DatabaseEmailTemplateResolverDao.java | 36 +++++++++++++++++++ .../service/EmailTemplateResolverService.java | 7 ++++ .../DatabaseEmailTemplateResolverService.java | 32 +++++++++++++++++ 5 files changed, 95 insertions(+) create mode 100644 core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java create mode 100644 core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java create mode 100644 core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java create mode 100644 core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-spring.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-spring.xml index c9db63e..6422858 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-spring.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-spring.xml @@ -6,4 +6,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java new file mode 100644 index 0000000..9c4df46 --- /dev/null +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java @@ -0,0 +1,9 @@ +package me.cxdev.commerce.toolkit.email.dao; + +import javassist.NotFoundException; + +import me.cxdev.commerce.toolkit.model.ThymeleafEmailTemplateModel; + +public interface EmailTemplateResolverDao { + ThymeleafEmailTemplateModel searchTemplate(String templateName) throws NotFoundException; +} diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java new file mode 100644 index 0000000..a0df683 --- /dev/null +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java @@ -0,0 +1,36 @@ +package me.cxdev.commerce.toolkit.email.dao.impl; + +import javassist.NotFoundException; + +import de.hybris.platform.servicelayer.search.FlexibleSearchQuery; +import de.hybris.platform.servicelayer.search.FlexibleSearchService; +import de.hybris.platform.servicelayer.search.SearchResult; + +import org.apache.log4j.Logger; + +import me.cxdev.commerce.toolkit.email.dao.EmailTemplateResolverDao; +import me.cxdev.commerce.toolkit.model.ThymeleafEmailTemplateModel; + +public class DatabaseEmailTemplateResolverDao implements EmailTemplateResolverDao { + + private static final Logger LOG = Logger.getLogger(DatabaseEmailTemplateResolverDao.class); + + private final String QUERY = "SELECT {pk} FROM {ThymeleafEmailTemplate} WHERE {code} = ?templateName"; + private final FlexibleSearchService flexibleSearchService; + + public DatabaseEmailTemplateResolverDao(FlexibleSearchService flexibleSearchService) { + this.flexibleSearchService = flexibleSearchService; + } + + public ThymeleafEmailTemplateModel searchTemplate(String templateName) throws NotFoundException { + FlexibleSearchQuery query = new FlexibleSearchQuery(QUERY); + query.addQueryParameter("templateName", templateName); + LOG.debug(String.format("Searching for email template with template name: %s", templateName)); + final SearchResult result = flexibleSearchService.search(query); + if (result.getResult().isEmpty()) { + LOG.error(String.format("No email template found for template name: %s", templateName)); + throw new NotFoundException(String.format("No email template found for template name: %s", templateName)); + } + return result.getResult().getFirst(); + } +} diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java new file mode 100644 index 0000000..7f9d6e7 --- /dev/null +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java @@ -0,0 +1,7 @@ +package me.cxdev.commerce.toolkit.email.service; + +import java.util.Locale; + +public interface EmailTemplateResolverService { + String resolveEmailTemplate(String templateName, Locale locale); +} diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java new file mode 100644 index 0000000..59aedda --- /dev/null +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java @@ -0,0 +1,32 @@ +package me.cxdev.commerce.toolkit.email.service.impl; + +import java.util.Locale; +import javassist.NotFoundException; + +import org.apache.commons.lang3.StringUtils; +import org.apache.log4j.Logger; + +import me.cxdev.commerce.toolkit.email.dao.EmailTemplateResolverDao; +import me.cxdev.commerce.toolkit.email.service.EmailTemplateResolverService; +import me.cxdev.commerce.toolkit.model.ThymeleafEmailTemplateModel; + +public class DatabaseEmailTemplateResolverService implements EmailTemplateResolverService { + private static final Logger LOG = Logger.getLogger(DatabaseEmailTemplateResolverService.class); + private final EmailTemplateResolverDao emailTemplateResolverDao; + + public DatabaseEmailTemplateResolverService(EmailTemplateResolverDao emailTemplateResolverDao) { + this.emailTemplateResolverDao = emailTemplateResolverDao; + } + + @Override + public String resolveEmailTemplate(String templateName, Locale locale) { + try { + ThymeleafEmailTemplateModel template = emailTemplateResolverDao.searchTemplate(templateName); + return template.getTemplate(locale); + } catch (NotFoundException e) { + LOG.error(String.format("An error occurred while searching for the email template: %s", e.getMessage())); + } + return StringUtils.EMPTY; + } + +} From 83f79a862b483040cb3dea1c61c7995563183dc2 Mon Sep 17 00:00:00 2001 From: Ole Ruhl Date: Tue, 9 Jun 2026 14:55:27 +0200 Subject: [PATCH 08/13] refactor: pass resolved template HTML directly into HtmlEmailBuilder instead of template name --- .../toolkit/email/HtmlEmailBuilder.java | 23 ++++++++++++------- .../toolkit/email/HtmlEmailGenerator.java | 3 ++- .../toolkit/email/HtmlEmailBuilderTests.java | 5 ++-- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java index e223b11..6da2ef7 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java @@ -34,7 +34,7 @@ static HtmlEmailBuilder withHtmlEmailGenerator(HtmlEmailGenerator generator) { private String subject; private String body; - private String templateName; + private String templateHtml; private Map contextParameters; private Locale templateLocale; @@ -114,9 +114,8 @@ public HtmlEmailBuilder body(String body) { return this; } - public HtmlEmailBuilder template(String template, Locale locale) { - this.templateName = template; - this.templateLocale = locale; + public HtmlEmailBuilder template(String template) { + this.templateHtml = template; return templateParameter(Map.of()); } @@ -133,6 +132,11 @@ public HtmlEmailBuilder templateParameter(Map parameters) { return this; } + public HtmlEmailBuilder templateLocale(Locale templateLocale) { + this.templateLocale = templateLocale; + return this; + } + public HtmlEmailBuilder attach(File file) { attach(HtmlEmailAttachmentBuilders.forFile(file)); return this; @@ -176,13 +180,16 @@ private void validateConfiguration() throws EmailException { throw new EmailException("Cannot create email without recipients. Please provide at least one valid email address!"); } - if (StringUtils.isBlank(body) && StringUtils.isBlank(templateName)) { + if (StringUtils.isBlank(body) && StringUtils.isBlank(templateHtml)) { throw new EmailException("Cannot create email without content. There must be a configuration for either body or template!"); } - if (StringUtils.isNotBlank(body) && StringUtils.isNotBlank(templateName)) { + if (StringUtils.isNotBlank(body) && StringUtils.isNotBlank(templateHtml)) { throw new EmailException("Cannot create email without ambiguous content. There must be a configuration for either body or template, not both!"); } + if (templateHtml != null && templateLocale == null) { + throw new EmailException("Email creation failed: missing configuration for templateLocale."); + } } private void configureAddresses(HtmlEmail htmlEmail) throws EmailException { @@ -201,11 +208,11 @@ private void configureAddresses(HtmlEmail htmlEmail) throws EmailException { } private void processMessageContent(HtmlEmail htmlEmail, HtmlEmailGenerator htmlEmailGenerator) throws EmailException { - if (templateName != null && templateLocale != null) { + if (templateHtml != null) { templateParameter("subject", subject); templateParameter("recipients", emptyIfNull(toAddresses)); templateParameter("ccRecipients", emptyIfNull(ccAddresses)); - body = htmlEmailGenerator.processTemplate(templateName, contextParameters, templateLocale); + body = htmlEmailGenerator.processTemplate(templateHtml, contextParameters, templateLocale); } htmlEmail.setSubject(subject); diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java index 99216a5..ce3bab2 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java @@ -88,7 +88,8 @@ default HtmlEmail createHtmlEmailFromTemplate(String subject, Collection templateParameters, Locale locale) throws EmailException { return newHtmlEmail() .subject(subject) - .template(template, locale) + .template(template) + .templateLocale(locale) .templateParameter(templateParameters) .custom(builder -> emptyIfNull(to).forEach(builder::to)) .custom(builder -> emptyIfNull(cc).forEach(builder::cc)) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java index 6b24ea1..c24b84f 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java @@ -50,7 +50,7 @@ public void failsWithBodyAndTemplate() throws EmailException { builder .to("mail@localhost") .body("body") - .template("template", Locale.ENGLISH) + .template("template") .build(); } @@ -141,7 +141,8 @@ public void testSubjectAndBody() throws Exception { public void testSubjectAndTemplate() throws Exception { HtmlEmail htmlEmail = builder .subject("custom subject for email") - .template("templateName", Locale.ENGLISH) + .template("templateName") + .templateLocale(Locale.ENGLISH) .to("requires-at-least-one-to-address@localhost") .build(); From c9731b8078d47fc94b6d3418671c74863cebcc8f Mon Sep 17 00:00:00 2001 From: Ole Ruhl Date: Tue, 9 Jun 2026 14:56:40 +0200 Subject: [PATCH 09/13] feat: expose ThymeleafEmailTemplate in Backoffice under CX DEV Tools --- .../cxdevtoolkit/project.properties | 24 -------------- .../cxdevtoolkit-backoffice-config.xml | 33 +++++++++++++++++++ .../labels_de.properties | 5 ++- .../labels_en.properties | 5 ++- .../cxdevtoolkit-locales_de.properties | 9 ++++- .../cxdevtoolkit-locales_en.properties | 9 ++++- 6 files changed, 57 insertions(+), 28 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/project.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/project.properties index bd2e400..cc80238 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/project.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/project.properties @@ -87,30 +87,6 @@ cxdevtoolkit.impeximport.environment.importtestdata=false # update.executeProjectData.extensionName.list=cxdevtoolkit ############################################################################## - -############################################################################## -# Html Email Service configuration -# -# The HtmlEmailService requires all templates to be stored within the following class paths: -# cxdevtoolkit/email-templates/html/** -# cxdevtoolkit/email-templates/text/** -# -# For localization of the emails, message bundles are preconfigured. Unfortunately, a message source cannot -# hold wildcards and, therefore, this extension has 5 prepared configuration paths that are resolved during -# system startup. If you want to contribute to the message bundle for email templates, please take one of the -# properties below, and change the path accordingly. The order is important, see note below! -# -# Note: You cannot simply add your messages to a file called cxdevtoolkit/email-templates/messages, because the message -# source will stop file resolving, after the first match, ie. a file already existing in a previous message -# source will stop the resolver from loading your keys from your local file with the same name. -############################################################################## -cxdevtoolkit.htmlEmailService.configuration.messagebundle1=classpath*:cxdevtoolkit/email-templates/messages -cxdevtoolkit.htmlEmailService.configuration.messagebundle2=classpath*:cxdevtoolkit/email-templates/messages -cxdevtoolkit.htmlEmailService.configuration.messagebundle3=classpath*:cxdevtoolkit/email-templates/messages -cxdevtoolkit.htmlEmailService.configuration.messagebundle4=classpath*:cxdevtoolkit/email-templates/messages -cxdevtoolkit.htmlEmailService.configuration.messagebundle5=classpath*:cxdevtoolkit/email-templates/messages - - ############################################################################## # Html Email Service Fake configuration # diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml index b19c6f0..0d56e6a 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml @@ -18,6 +18,9 @@ + + + @@ -79,4 +82,34 @@ + + + + + + 'Email Template' + (code != null ? '' + ': ' + code : '') + + + + + + + + + + + + + + + + rows + 15 + + + + + + + \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties index 84e0a38..4c5a39b 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties @@ -1,2 +1,5 @@ cxdevtools_treenode_main=CX DEV Tools -cxdevtools_treenode_fakemail=Fake Mails \ No newline at end of file +cxdevtools_treenode_fakemail=Fake Mails +cxdevtools_treenode_email=E-Mail + +thymeleaf.template.content=Template Inhalt \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties index 84e0a38..e44ac61 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties @@ -1,2 +1,5 @@ cxdevtools_treenode_main=CX DEV Tools -cxdevtools_treenode_fakemail=Fake Mails \ No newline at end of file +cxdevtools_treenode_fakemail=Fake Mails +cxdevtools_treenode_email=Email + +thymeleaf.template.content=Template Content \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties index 02ac30d..f3158f4 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties @@ -1,4 +1,11 @@ type.LocallyStoredEmail.name=Lokale Email type.LocallyStoredEmail.description=Lokal gespeicherte Email durch einen Fake Service, anstatt sie via SMTP zu versenden. type.LocallyStoredEmail.sender.name=Absender -type.LocallyStoredEmail.recipients.name=Empfänger \ No newline at end of file +type.LocallyStoredEmail.recipients.name=Empf�nger + +type.ThymeleafEmailTemplate.name=E-Mail-Template +type.ThymeleafEmailTemplate.description=Speichert lokalisierte HTML-Vorlagen, die von der Thymeleaf-Engine für E-Mails verwendet werden. +type.ThymeleafEmailTemplate.code.name=Template-Name +type.ThymeleafEmailTemplate.code.description=Eindeutige Kennung zur Auflösung der Vorlage (z. B. 'contact', 'registration') +type.ThymeleafEmailTemplate.template.name=HTML-Vorlage +type.ThymeleafEmailTemplate.template.description=Roher HTML-Code, der das Thymeleaf-Markup für den E-Mail-Body enth�lt \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_en.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_en.properties index 4b5b9a7..1b34696 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_en.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_en.properties @@ -1,4 +1,11 @@ type.LocallyStoredEmail.name=Local Email type.LocallyStoredEmail.description=Email stored locally by a fake service instead of sending them via SMTP. type.LocallyStoredEmail.sender.name=Sender -type.LocallyStoredEmail.recipients.name=Recipients \ No newline at end of file +type.LocallyStoredEmail.recipients.name=Recipients + +type.ThymeleafEmailTemplate.name=Email Template +type.ThymeleafEmailTemplate.description=Stores localized HTML templates processed by the Thymeleaf engine for emails. +type.ThymeleafEmailTemplate.code.name=Template Name +type.ThymeleafEmailTemplate.code.description=Unique identifier used to resolve the template (e.g., 'contact', 'registration') +type.ThymeleafEmailTemplate.template.name=HTML Template +type.ThymeleafEmailTemplate.template.description=Raw HTML code containing the Thymeleaf markup for the email body \ No newline at end of file From 0dda55ee5434ad95cc3b42b730a7712c913fe948 Mon Sep 17 00:00:00 2001 From: Ole Ruhl Date: Tue, 9 Jun 2026 14:57:01 +0200 Subject: [PATCH 10/13] chore: remove obsolete classpath message bundle configuration --- .../resources/cxdevtoolkit/thymeleafemails-spring.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit/thymeleafemails-spring.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit/thymeleafemails-spring.xml index ea3def5..fbbe24a 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit/thymeleafemails-spring.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit/thymeleafemails-spring.xml @@ -53,15 +53,6 @@ - - - ${cxdevtoolkit.htmlEmailService.configuration.messagebundle1} - ${cxdevtoolkit.htmlEmailService.configuration.messagebundle2} - ${cxdevtoolkit.htmlEmailService.configuration.messagebundle3} - ${cxdevtoolkit.htmlEmailService.configuration.messagebundle4} - ${cxdevtoolkit.htmlEmailService.configuration.messagebundle5} - - From 6825d58e8fea4db592dce0c8a3d2d4bcc37fe302 Mon Sep 17 00:00:00 2001 From: Ole Ruhl Date: Tue, 9 Jun 2026 14:57:12 +0200 Subject: [PATCH 11/13] docs: update README for database-driven Thymeleaf email template management --- .../custom/cxdevtools/cxdevtoolkit/README.md | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/README.md b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/README.md index 57f1f7f..ceb90ab 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/README.md +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/README.md @@ -121,16 +121,49 @@ the configuration file `systemsetup-spring.xml` and inspect the project data imp ## Centralized HtmlEmail handling -The main purpose of these services is, to provide a simple way of sending emails to the customers, without making use of the `CMSComponents` -like with the standard way of mailing within the SAP Commerce Cloud, provided by the `acceleratorservices` extension. The implementation -makes use of the [Thymeleaf rendering engine](https://www.thymeleaf.org/), i.e. you are able to define your mails as thymeleaf templates -and provide localized messages to it. - -The `HtmlEmailGenerator` services (registered as bean with name `thymeleafHtmlEmailGenerator` and alias `htmlEmailGenerator`) should be used -to create `HtmlEmail` objects, whenever you want to send an email, e.g. from Workflows or from EventListeners. The class provides a simple -and an enhanced mechanism to create `HtmlEmail` objects. The simple way takes a `String` as a body and sets it as HTML body for the email. -The enhanced mechanism takes a template name and context parameters. The template is resolves from the classpath and the template engine is -executed with the provided context parameters. +The main purpose of these services is to provide a simple way of sending emails without relying on CMSComponents, as +required by the standard SAP Commerce Cloud acceleratorservices approach. The implementation uses the Thymeleaf +rendering engine. + +### Template resolution + +Email templates are stored as localized `ThymeleafEmailTemplate` items in the database and can be managed via +Backoffice (under *CX DEV Tools → Email*) or Impex. + +At runtime, `EmailTemplateResolverService` (impl: `DatabaseEmailTemplateResolverService`) resolves the matching +`ThymeleafEmailTemplate` by `code` and locale, and passes the localized HTML content to `HtmlEmailBuilder` for +Thymeleaf rendering. + +### Impex import + +Templates can be created or updated via Impex: + + ```impex + INSERT_UPDATE ThymeleafEmailTemplate; code[unique = true]; template[lang = de] ; template[lang = en] + ; contact ; " + + +

+

+ + " ; + ``` + +**Impex workaround for Thymeleaf expressions:** Impex interprets `${...}` as its own variable syntax. To work around +this: + +- Define the macro `$d=$` at the top of the Impex file. This causes `$d{...}` to be resolved to `${...}` during + import. +- Use `$d{...}` instead of `${...}` for all Thymeleaf expressions in the file. +- Escape all double quotes inside HTML values by doubling them (`"` → `""`). + + +### HtmlEmailGenerator (programmatic use) + +The `HtmlEmailGenerator` bean (`thymeleafHtmlEmailGenerator` / alias `htmlEmailGenerator`) remains available for +programmatic email creation, e.g. from Workflows or EventListeners. It provides a simple mode (plain HTML string as +body) and an enhanced mode (template code + locale + context parameters). + ### How to activate and use From 105e3048506ae19f8b528da3b1c062e789d58929 Mon Sep 17 00:00:00 2001 From: Ole Ruhl Date: Mon, 15 Jun 2026 11:55:21 +0200 Subject: [PATCH 12/13] address review comments: add TemplateNotFoundException, rename templateLocale to locale, replace javassist NotFoundException with UnknownIdentifierException --- .../cxdevtoolkit-backoffice-config.xml | 4 ++-- .../labels_de.properties | 2 +- .../labels_en.properties | 2 +- .../cxdevtoolkit-locales_de.properties | 12 +++++----- .../toolkit/email/HtmlEmailBuilder.java | 6 ++--- .../toolkit/email/HtmlEmailGenerator.java | 2 +- .../email/dao/EmailTemplateResolverDao.java | 17 ++++++++++++-- .../DatabaseEmailTemplateResolverDao.java | 8 +++---- .../exception/TemplateNotFoundException.java | 7 ++++++ .../service/EmailTemplateResolverService.java | 22 ++++++++++++++++++- .../DatabaseEmailTemplateResolverService.java | 14 +++++------- .../toolkit/email/HtmlEmailBuilderTests.java | 2 +- 12 files changed, 66 insertions(+), 32 deletions(-) create mode 100644 core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/exception/TemplateNotFoundException.java diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml index 0d56e6a..41af466 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-config.xml @@ -19,7 +19,7 @@ - + @@ -100,7 +100,7 @@ - + rows diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties index 4c5a39b..ee61ccf 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_de.properties @@ -2,4 +2,4 @@ cxdevtools_treenode_main=CX DEV Tools cxdevtools_treenode_fakemail=Fake Mails cxdevtools_treenode_email=E-Mail -thymeleaf.template.content=Template Inhalt \ No newline at end of file +cxdevtools_section_ThymeleafEmailTemplate_content=Template Inhalt \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties index e44ac61..d265183 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/cxdevtoolkit-backoffice-labels/labels_en.properties @@ -2,4 +2,4 @@ cxdevtools_treenode_main=CX DEV Tools cxdevtools_treenode_fakemail=Fake Mails cxdevtools_treenode_email=Email -thymeleaf.template.content=Template Content \ No newline at end of file +cxdevtools_section_ThymeleafEmailTemplate_content=Template Content \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties index f3158f4..1d58e82 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/resources/localization/cxdevtoolkit-locales_de.properties @@ -1,11 +1,11 @@ -type.LocallyStoredEmail.name=Lokale Email -type.LocallyStoredEmail.description=Lokal gespeicherte Email durch einen Fake Service, anstatt sie via SMTP zu versenden. +type.LocallyStoredEmail.name=Lokale E-Mail +type.LocallyStoredEmail.description=Lokal gespeicherte E-Mail durch einen Fake Service, anstatt sie via SMTP zu versenden. type.LocallyStoredEmail.sender.name=Absender -type.LocallyStoredEmail.recipients.name=Empf�nger +type.LocallyStoredEmail.recipients.name=Empf\u00E4nger type.ThymeleafEmailTemplate.name=E-Mail-Template -type.ThymeleafEmailTemplate.description=Speichert lokalisierte HTML-Vorlagen, die von der Thymeleaf-Engine für E-Mails verwendet werden. +type.ThymeleafEmailTemplate.description=Speichert lokalisierte HTML-Vorlagen, die von der Thymeleaf-Engine f\u00FCr E-Mails verwendet werden. type.ThymeleafEmailTemplate.code.name=Template-Name -type.ThymeleafEmailTemplate.code.description=Eindeutige Kennung zur Auflösung der Vorlage (z. B. 'contact', 'registration') +type.ThymeleafEmailTemplate.code.description=Eindeutige Kennung zur Aufl\u00F6sung der Vorlage (z. B. 'contact', 'registration') type.ThymeleafEmailTemplate.template.name=HTML-Vorlage -type.ThymeleafEmailTemplate.template.description=Roher HTML-Code, der das Thymeleaf-Markup für den E-Mail-Body enth�lt \ No newline at end of file +type.ThymeleafEmailTemplate.template.description=Roher HTML-Code, der das Thymeleaf-Markup f\u00FCr den E-Mail-Body enth\u00E4lt \ No newline at end of file diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java index 6da2ef7..10e04b9 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailBuilder.java @@ -132,8 +132,8 @@ public HtmlEmailBuilder templateParameter(Map parameters) { return this; } - public HtmlEmailBuilder templateLocale(Locale templateLocale) { - this.templateLocale = templateLocale; + public HtmlEmailBuilder locale(Locale locale) { + this.templateLocale = locale; return this; } @@ -188,7 +188,7 @@ private void validateConfiguration() throws EmailException { throw new EmailException("Cannot create email without ambiguous content. There must be a configuration for either body or template, not both!"); } if (templateHtml != null && templateLocale == null) { - throw new EmailException("Email creation failed: missing configuration for templateLocale."); + throw new EmailException("Email creation failed: missing configuration for locale."); } } diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java index ce3bab2..65f7d76 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/HtmlEmailGenerator.java @@ -89,7 +89,7 @@ default HtmlEmail createHtmlEmailFromTemplate(String subject, Collection emptyIfNull(to).forEach(builder::to)) .custom(builder -> emptyIfNull(cc).forEach(builder::cc)) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java index 9c4df46..670045e 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/EmailTemplateResolverDao.java @@ -1,9 +1,22 @@ package me.cxdev.commerce.toolkit.email.dao; -import javassist.NotFoundException; +import de.hybris.platform.servicelayer.exceptions.UnknownIdentifierException; import me.cxdev.commerce.toolkit.model.ThymeleafEmailTemplateModel; +/** + * DAO for retrieving {@link ThymeleafEmailTemplateModel} instances from the database. + * + *

Implementations query the {@code ThymeleafEmailTemplate} type by its unique code + * using FlexibleSearch. + */ public interface EmailTemplateResolverDao { - ThymeleafEmailTemplateModel searchTemplate(String templateName) throws NotFoundException; + /** + * Searches for a {@link ThymeleafEmailTemplateModel} by its unique code. + * + * @param templateName the unique code of the template (e.g. {@code "contact"}, {@code "registration"}) + * @return the matching {@link ThymeleafEmailTemplateModel}, never {@code null} + * @throws UnknownIdentifierException if no template with the given code exists in the database + */ + ThymeleafEmailTemplateModel searchTemplate(String templateName) throws UnknownIdentifierException; } diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java index a0df683..af2df90 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/dao/impl/DatabaseEmailTemplateResolverDao.java @@ -1,7 +1,6 @@ package me.cxdev.commerce.toolkit.email.dao.impl; -import javassist.NotFoundException; - +import de.hybris.platform.servicelayer.exceptions.UnknownIdentifierException; import de.hybris.platform.servicelayer.search.FlexibleSearchQuery; import de.hybris.platform.servicelayer.search.FlexibleSearchService; import de.hybris.platform.servicelayer.search.SearchResult; @@ -22,14 +21,13 @@ public DatabaseEmailTemplateResolverDao(FlexibleSearchService flexibleSearchServ this.flexibleSearchService = flexibleSearchService; } - public ThymeleafEmailTemplateModel searchTemplate(String templateName) throws NotFoundException { + public ThymeleafEmailTemplateModel searchTemplate(String templateName) throws UnknownIdentifierException { FlexibleSearchQuery query = new FlexibleSearchQuery(QUERY); query.addQueryParameter("templateName", templateName); LOG.debug(String.format("Searching for email template with template name: %s", templateName)); final SearchResult result = flexibleSearchService.search(query); if (result.getResult().isEmpty()) { - LOG.error(String.format("No email template found for template name: %s", templateName)); - throw new NotFoundException(String.format("No email template found for template name: %s", templateName)); + throw new UnknownIdentifierException(String.format("No email template found for template name: %s", templateName)); } return result.getResult().getFirst(); } diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/exception/TemplateNotFoundException.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/exception/TemplateNotFoundException.java new file mode 100644 index 0000000..cd265e7 --- /dev/null +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/exception/TemplateNotFoundException.java @@ -0,0 +1,7 @@ +package me.cxdev.commerce.toolkit.email.exception; + +public class TemplateNotFoundException extends RuntimeException { + public TemplateNotFoundException(String message) { + super(message); + } +} diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java index 7f9d6e7..6d3f2ec 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/EmailTemplateResolverService.java @@ -2,6 +2,26 @@ import java.util.Locale; +import me.cxdev.commerce.toolkit.email.exception.TemplateNotFoundException; + +/** + * Resolves localized email templates by name from the database. + * + *

Templates are stored as localized items in the database and can be managed + * via Backoffice or Impex. At runtime this service looks up the matching template + * by name and locale and returns its raw HTML content for further processing by + * the Thymeleaf rendering engine. + */ + public interface EmailTemplateResolverService { - String resolveEmailTemplate(String templateName, Locale locale); + /** + * Returns the raw HTML content of the named template for the given locale. + * + * @param templateName logical name of the template (e.g. {@code "contact"}, {@code "registration"}) + * @param locale the locale used to select the localized template variant + * @return the resolved HTML template content, never {@code null} + * @throws TemplateNotFoundException if no template with the given name exists for the requested locale + */ + + String resolveEmailTemplate(String templateName, Locale locale) throws TemplateNotFoundException; } diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java index 59aedda..cfe625c 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/src/me/cxdev/commerce/toolkit/email/service/impl/DatabaseEmailTemplateResolverService.java @@ -1,17 +1,15 @@ package me.cxdev.commerce.toolkit.email.service.impl; import java.util.Locale; -import javassist.NotFoundException; -import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; +import de.hybris.platform.servicelayer.exceptions.UnknownIdentifierException; import me.cxdev.commerce.toolkit.email.dao.EmailTemplateResolverDao; +import me.cxdev.commerce.toolkit.email.exception.TemplateNotFoundException; import me.cxdev.commerce.toolkit.email.service.EmailTemplateResolverService; import me.cxdev.commerce.toolkit.model.ThymeleafEmailTemplateModel; public class DatabaseEmailTemplateResolverService implements EmailTemplateResolverService { - private static final Logger LOG = Logger.getLogger(DatabaseEmailTemplateResolverService.class); private final EmailTemplateResolverDao emailTemplateResolverDao; public DatabaseEmailTemplateResolverService(EmailTemplateResolverDao emailTemplateResolverDao) { @@ -19,14 +17,12 @@ public DatabaseEmailTemplateResolverService(EmailTemplateResolverDao emailTempla } @Override - public String resolveEmailTemplate(String templateName, Locale locale) { + public String resolveEmailTemplate(String templateName, Locale locale) throws TemplateNotFoundException { try { ThymeleafEmailTemplateModel template = emailTemplateResolverDao.searchTemplate(templateName); return template.getTemplate(locale); - } catch (NotFoundException e) { - LOG.error(String.format("An error occurred while searching for the email template: %s", e.getMessage())); + } catch (UnknownIdentifierException e) { + throw new TemplateNotFoundException(String.format("An error occurred while searching for the email template: %s", e.getMessage())); } - return StringUtils.EMPTY; } - } diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java index c24b84f..9d31abb 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/testsrc/me/cxdev/commerce/toolkit/email/HtmlEmailBuilderTests.java @@ -142,7 +142,7 @@ public void testSubjectAndTemplate() throws Exception { HtmlEmail htmlEmail = builder .subject("custom subject for email") .template("templateName") - .templateLocale(Locale.ENGLISH) + .locale(Locale.ENGLISH) .to("requires-at-least-one-to-address@localhost") .build(); From 289946b06437f817141bfb3a37a5ff39866ed13a Mon Sep 17 00:00:00 2001 From: Stefan Bechtold Date: Mon, 15 Jun 2026 13:52:29 +0200 Subject: [PATCH 13/13] set release version of extensions to 5.0.2 --- .../bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevbackoffice/external-dependencies.xml | 2 +- .../bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevenvconfig/external-dependencies.xml | 2 +- .../hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml | 2 +- .../bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml | 2 +- .../bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevreporting/external-dependencies.xml | 2 +- .../hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml | 2 +- .../custom/cxdevtools/cxdevtoolkit/external-dependencies.xml | 2 +- sonar-project.properties | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml index c72b659..70b864f 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/extensioninfo.xml @@ -1,6 +1,6 @@ - + diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml index fa2b633..e4394ae 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevbackoffice/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevbackoffice - 5.0.2-snapshot + 5.0.2 jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml index 1a60adb..b224d53 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/extensioninfo.xml @@ -1,7 +1,7 @@ + name="cxdevenvconfig" version="5.0.2" usemaven="true"> diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml index 40b66b5..d3d7650 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevenvconfig/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevenvconfig - 5.0.2-snapshot + 5.0.2 jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml index d82b9b4..4c074ef 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/extensioninfo.xml @@ -1,6 +1,6 @@ - + diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml index b2d98f9..9c34a07 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevproxy/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevproxy - 5.0.2-snapshot + 5.0.2 jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml index fceb231..16a87fc 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/extensioninfo.xml @@ -1,6 +1,6 @@ - + diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml index deb03f4..a0c454c 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevreporting/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevreporting - 5.0.2-snapshot + 5.0.2 jar diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml index 846cc5d..7f04960 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/extensioninfo.xml @@ -1,7 +1,7 @@ + name="cxdevtoolkit" version="5.0.2" usemaven="true"> diff --git a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml index 1c46302..fbd076c 100644 --- a/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml +++ b/core-customize/hybris/bin/custom/cxdevtools/cxdevtoolkit/external-dependencies.xml @@ -3,7 +3,7 @@ 4.0.0 me.cxdev cxdevtoolkit - 5.0.2-snapshot + 5.0.2 jar diff --git a/sonar-project.properties b/sonar-project.properties index 72f3a76..b507d7d 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.organization=cxdevtools # This is the name and version displayed in the SonarCloud UI. sonar.projectName=cxdevtools-workspace -sonar.projectVersion=5.0.2-snapshot +sonar.projectVersion=5.0.2 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. sonar.sources=core-customize/hybris/bin/custom/cxdevtools