From 9c37da0ee999be2106905543fbd59722cf1c6761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couralet?= Date: Tue, 3 Sep 2019 14:13:57 +0200 Subject: [PATCH] KEYCLOAK-8818 Support message bundle in theme resources --- .../keycloak/theme/ThemeResourceProvider.java | 20 +++++++++++-- ...ClasspathThemeResourceProviderFactory.java | 30 ++++++++++++++++--- .../keycloak/theme/ExtendingThemeManager.java | 6 +++- .../messages/messages_en.properties | 2 ++ .../theme/ThemeResourceProviderTest.java | 18 +++++++++-- 5 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme-resources/messages/messages_en.properties diff --git a/server-spi/src/main/java/org/keycloak/theme/ThemeResourceProvider.java b/server-spi/src/main/java/org/keycloak/theme/ThemeResourceProvider.java index d647f54136..fb06b6d371 100755 --- a/server-spi/src/main/java/org/keycloak/theme/ThemeResourceProvider.java +++ b/server-spi/src/main/java/org/keycloak/theme/ThemeResourceProvider.java @@ -17,12 +17,13 @@ package org.keycloak.theme; -import org.keycloak.provider.Provider; - import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.Set; +import java.util.Locale; +import java.util.Properties; + +import org.keycloak.provider.Provider; /** * A theme resource provider can be used to load additional templates and resources. An example use of this would be @@ -53,4 +54,17 @@ public interface ThemeResourceProvider extends Provider { */ InputStream getResourceAsStream(String path) throws IOException; + /** + * Load the message bundle for the specific name and locale + * + * @param baseBundlename The base name of the bundle, such as "messages" in + * messages_en.properties. + * @param locale The locale of the desired message bundle. + * @return The localized messages from the bundle. + * @throws IOException If bundle can not be read. + */ + default Properties getMessages(String baseBundlename, Locale locale) throws IOException{ + return new Properties(); + } + } diff --git a/services/src/main/java/org/keycloak/theme/ClasspathThemeResourceProviderFactory.java b/services/src/main/java/org/keycloak/theme/ClasspathThemeResourceProviderFactory.java index 760bbace6e..6af4073f2d 100644 --- a/services/src/main/java/org/keycloak/theme/ClasspathThemeResourceProviderFactory.java +++ b/services/src/main/java/org/keycloak/theme/ClasspathThemeResourceProviderFactory.java @@ -1,17 +1,24 @@ package org.keycloak.theme; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Locale; +import java.util.Properties; + import org.keycloak.Config; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - public class ClasspathThemeResourceProviderFactory implements ThemeResourceProviderFactory, ThemeResourceProvider { public static final String THEME_RESOURCES_TEMPLATES = "theme-resources/templates/"; public static final String THEME_RESOURCES_RESOURCES = "theme-resources/resources/"; + public static final String THEME_RESOURCES_MESSAGES = "theme-resources/messages/"; + private final String id; private final ClassLoader classLoader; @@ -35,6 +42,21 @@ public class ClasspathThemeResourceProviderFactory implements ThemeResourceProvi return classLoader.getResourceAsStream(THEME_RESOURCES_RESOURCES + path); } + @Override + public Properties getMessages(String baseBundlename, Locale locale) throws IOException { + Properties m = new Properties(); + InputStream in = classLoader.getResourceAsStream(THEME_RESOURCES_MESSAGES + baseBundlename + "_" + locale.toString() + ".properties"); + if(in != null){ + Charset encoding = PropertiesUtil.detectEncoding(in); + // detectEncoding closes the stream + try (Reader reader = new InputStreamReader( + classLoader.getResourceAsStream(THEME_RESOURCES_MESSAGES + baseBundlename + "_" + locale.toString() + ".properties"), encoding)) { + m.load(reader); + } + } + return m; + } + @Override public String getId() { return id; diff --git a/services/src/main/java/org/keycloak/theme/ExtendingThemeManager.java b/services/src/main/java/org/keycloak/theme/ExtendingThemeManager.java index b580a4a316..77413abcc5 100755 --- a/services/src/main/java/org/keycloak/theme/ExtendingThemeManager.java +++ b/services/src/main/java/org/keycloak/theme/ExtendingThemeManager.java @@ -257,6 +257,10 @@ public class ExtendingThemeManager implements ThemeProvider { messages.putAll(getMessages(baseBundlename, Locale.ENGLISH)); } + for (ThemeResourceProvider t : themeResourceProviders ){ + messages.putAll(t.getMessages(baseBundlename, locale)); + } + ListIterator itr = themes.listIterator(themes.size()); while (itr.hasPrevious()) { Properties m = itr.previous().getMessages(baseBundlename, locale); @@ -264,7 +268,7 @@ public class ExtendingThemeManager implements ThemeProvider { messages.putAll(m); } } - + this.messages.putIfAbsent(baseBundlename, new ConcurrentHashMap()); this.messages.get(baseBundlename).putIfAbsent(locale, messages); diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme-resources/messages/messages_en.properties b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme-resources/messages/messages_en.properties new file mode 100644 index 0000000000..2e7c5f04bf --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme-resources/messages/messages_en.properties @@ -0,0 +1,2 @@ +test.keycloak-8818= Hello from theme-resources +fullName=Full name (Theme-resources) \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java index 5373cb06ba..b6194c55fc 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java @@ -1,5 +1,8 @@ package org.keycloak.testsuite.theme; +import java.io.IOException; +import java.util.Locale; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Assert; @@ -10,8 +13,6 @@ import org.keycloak.testsuite.runonserver.RunOnServerDeployment; import org.keycloak.theme.Theme; import org.keycloak.theme.ThemeProvider; -import java.io.IOException; - public class ThemeResourceProviderTest extends AbstractTestRealmKeycloakTest { @Deployment @@ -50,4 +51,17 @@ public class ThemeResourceProviderTest extends AbstractTestRealmKeycloakTest { }); } + @Test + public void getMessages() { + testingClient.server().run(session -> { + try { + ThemeProvider extending = session.getProvider(ThemeProvider.class, "extending"); + Theme theme = extending.getTheme("base", Theme.Type.LOGIN); + Assert.assertNotNull(theme.getMessages("messages", Locale.ENGLISH).get("test.keycloak-8818")); + Assert.assertNotEquals("Full name (Theme-resources)", theme.getMessages("messages", Locale.ENGLISH).get("fullName")); + } catch (IOException e) { + Assert.fail(e.getMessage()); + } + }); + } }