You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2022/03/18 11:57:55 UTC

[myfaces-tobago] branch tobago-5.x updated: feat: Make selected theme storeable in session

This is an automated email from the ASF dual-hosted git repository.

lofwyr pushed a commit to branch tobago-5.x
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git


The following commit(s) were added to refs/heads/tobago-5.x by this push:
     new 942f003  feat: Make selected theme storeable in session
942f003 is described below

commit 942f003c727d879c3c5095403d5483a39fe2f51e
Author: Udo Schnurpfeil <ud...@irian.eu>
AuthorDate: Fri Mar 18 12:56:28 2022 +0100

    feat: Make selected theme storeable in session
    
    issue: TOBAGO-2119
---
 .../apache/myfaces/tobago/config/TobagoConfig.java | 24 ++++++++-
 .../org/apache/myfaces/tobago/context/Theme.java   |  6 +++
 .../myfaces/tobago/context/TobagoContext.java      | 58 ++++++++++++++++++----
 .../internal/config/TobagoConfigFragment.java      |  9 ++++
 .../tobago/internal/config/TobagoConfigMerger.java |  5 ++
 .../tobago/internal/config/TobagoConfigParser.java |  6 +++
 .../internal/renderkit/renderer/PageRenderer.java  |  7 ---
 .../myfaces/tobago/internal/util/CookieUtils.java  | 15 +++---
 .../myfaces/tobago/config/tobago-config-5.1.xsd    |  7 +++
 .../config/TobagoConfigParserUnitTest.java         | 16 ++++++
 .../src/test/resources/tobago-config-5.1.xml       |  1 +
 .../src/main/webapp/WEB-INF/tobago-config.xml      |  2 +
 12 files changed, 128 insertions(+), 28 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/config/TobagoConfig.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/config/TobagoConfig.java
index 0a74f32..7e447b3 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/config/TobagoConfig.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/config/TobagoConfig.java
@@ -56,6 +56,7 @@ public class TobagoConfig {
   private String defaultThemeName;
   private Map<String, ThemeImpl> availableThemes;
   private boolean themeCookie;
+  private boolean themeSession;
   private boolean createSessionSecret;
   private boolean checkSessionSecret;
   private boolean preventFrameAttacks;
@@ -106,6 +107,7 @@ public class TobagoConfig {
     supportedThemes = new ArrayList<>();
     availableThemes = new HashMap<>();
     themeCookie = true;
+    themeSession = false;
     createSessionSecret = true;
     checkSessionSecret = true;
     preventFrameAttacks = true;
@@ -173,6 +175,15 @@ public class TobagoConfig {
       LOG.debug("searching theme: null");
       return defaultTheme;
     }
+    final Theme found = getThemeIfExists(name);
+    if (found != null) {
+      return found;
+    }
+    LOG.debug("searching theme '{}' not found. Using default: {}", name, defaultTheme);
+    return defaultTheme;
+  }
+
+  public Theme getThemeIfExists(final String name) {
     if (defaultTheme != null && defaultTheme.getName().equals(name)) {
       return defaultTheme;
     }
@@ -181,8 +192,7 @@ public class TobagoConfig {
         return theme;
       }
     }
-    LOG.debug("searching theme '{}' not found. Using default: {}", name, defaultTheme);
-    return defaultTheme;
+    return null;
   }
 
   public void setDefaultThemeName(final String defaultThemeName) {
@@ -229,6 +239,14 @@ public class TobagoConfig {
     this.themeCookie = themeCookie;
   }
 
+  public boolean isThemeSession() {
+    return themeSession;
+  }
+
+  public void setThemeSession(boolean themeSession) {
+    this.themeSession = themeSession;
+  }
+
   public boolean isCreateSessionSecret() {
     return createSessionSecret;
   }
@@ -354,6 +372,8 @@ public class TobagoConfig {
     builder.append(availableThemes.keySet());
     builder.append(", \nthemeCookie=");
     builder.append(themeCookie);
+    builder.append(", \nthemeSession=");
+    builder.append(themeSession);
     builder.append(", \ncreateSessionSecret=");
     builder.append(createSessionSecret);
     builder.append(", \ncheckSessionSecret=");
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/Theme.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/Theme.java
index 1d66127..8b5c630 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/Theme.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/Theme.java
@@ -24,6 +24,12 @@ import org.apache.myfaces.tobago.component.Tags;
 import java.util.List;
 
 public interface Theme {
+
+  /**
+   * Internal key to manage the configured theme for the user.
+   */
+  String THEME_KEY = "tobago.theme";
+
   String getName();
 
   List<Theme> getFallbackList();
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoContext.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoContext.java
index bdcde17..f2a4ae5 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoContext.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/context/TobagoContext.java
@@ -30,6 +30,8 @@ import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.inject.Named;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
 import java.io.Serializable;
 import java.lang.invoke.MethodHandles;
 import java.util.Locale;
@@ -84,29 +86,63 @@ public class TobagoContext implements Serializable {
 
   public Theme getTheme() {
 
-    if (theme == null) {
-      final FacesContext facesContext = FacesContext.getCurrentInstance();
-      final ExternalContext externalContext = facesContext.getExternalContext();
+    if (theme != null) {
+      return theme;
+    }
 
-      final String themeName;
-      final Object request = externalContext.getRequest();
-      if (request instanceof HttpServletRequest && getTobagoConfig().isThemeCookie()) {
-        themeName = CookieUtils.getThemeNameFromCookie((HttpServletRequest) request);
-      } else {
-        themeName = null;
+    final FacesContext facesContext = FacesContext.getCurrentInstance();
+    final ExternalContext externalContext = facesContext.getExternalContext();
+    final Object request = externalContext.getRequest();
+    final Object session = externalContext.getSession(false);
+
+    // load theme from session
+    if (session instanceof HttpSession && getTobagoConfig().isThemeSession()) {
+      final String themeName = (String) ((HttpSession) session).getAttribute(Theme.THEME_KEY);
+      theme = getTobagoConfig().getThemeIfExists(themeName);
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("from session theme='{}'", theme.getName());
       }
+    }
+
+    if (theme != null) {
+      return theme;
+    }
 
+    // or load it from cookie
+    if (request instanceof HttpServletRequest && getTobagoConfig().isThemeCookie()) {
+      final String themeName = CookieUtils.getThemeNameFromCookie((HttpServletRequest) request);
       theme = getTobagoConfig().getTheme(themeName);
       if (LOG.isDebugEnabled()) {
-        LOG.debug("theme='{}'", theme.getName());
+        LOG.debug("from cookie theme='{}'", theme.getName());
       }
     }
 
-    return theme;
+    if (theme != null) {
+      return theme;
+    }
+
+    // or use default
+    return getTobagoConfig().getDefaultTheme();
   }
 
   public void setTheme(final Theme theme) {
     this.theme = theme;
+
+    final FacesContext facesContext = FacesContext.getCurrentInstance();
+    final ExternalContext externalContext = facesContext.getExternalContext();
+    final Object request = externalContext.getRequest();
+    final Object response = externalContext.getResponse();
+    final Object session = externalContext.getSession(false);
+
+    // save theme in cookie
+    if (response instanceof HttpServletResponse && request instanceof HttpServletRequest
+        && getTobagoConfig().isThemeCookie()) {
+      CookieUtils.setThemeNameToCookie((HttpServletRequest) request, (HttpServletResponse) response, theme.getName());
+    }
+    // save theme in session
+    if (session instanceof HttpSession && getTobagoConfig().isThemeSession()) {
+      ((HttpSession) session).setAttribute(Theme.THEME_KEY, theme.getName());
+    }
   }
 
   public UserAgent getUserAgent() {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigFragment.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigFragment.java
index e7a8f63..2990bcb 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigFragment.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigFragment.java
@@ -37,6 +37,7 @@ public class TobagoConfigFragment {
   private final List<String> supportedThemeNames;
   private String defaultThemeName;
   private Boolean themeCookie;
+  private Boolean themeSession;
   private Boolean createSessionSecret;
   private Boolean checkSessionSecret;
   private Boolean preventFrameAttacks;
@@ -115,6 +116,14 @@ public class TobagoConfigFragment {
     this.themeCookie = Boolean.valueOf(themeCookie);
   }
 
+  public Boolean getThemeSession() {
+    return themeSession;
+  }
+
+  public void setThemeSession(final String themeSession) {
+    this.themeSession = Boolean.valueOf(themeSession);
+  }
+
   public Boolean getCreateSessionSecret() {
     return createSessionSecret;
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java
index c2f29b4..80a20fa 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java
@@ -77,6 +77,11 @@ public class TobagoConfigMerger {
         tobagoConfig.setThemeCookie(fragment.getThemeCookie());
       }
 
+      // theme session
+      if (fragment.getThemeSession() != null) {
+        tobagoConfig.setThemeSession(fragment.getThemeSession());
+      }
+
       // session secret
       if (fragment.getCreateSessionSecret() != null) {
         tobagoConfig.setCreateSessionSecret(fragment.getCreateSessionSecret());
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java
index 6c711ec..dd04ec2 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParser.java
@@ -59,6 +59,7 @@ public class TobagoConfigParser extends TobagoConfigEntityResolver {
   private static final int DEFAULT_THEME = -114431171;
   private static final int SUPPORTED_THEME = -822303766;
   private static final int THEME_COOKIE = 1930664680;
+  private static final int THEME_SESSION = 753861266;
   private static final int CREATE_SESSION_SECRET = 413906616;
   private static final int CHECK_SESSION_SECRET = 275994924;
   private static final int PREVENT_FRAME_ATTACKS = 270456726;
@@ -290,6 +291,7 @@ public class TobagoConfigParser extends TobagoConfigEntityResolver {
       case DEFAULT_THEME:
       case SUPPORTED_THEME:
       case THEME_COOKIE:
+      case THEME_SESSION:
       case SUPPORTED_MARKUP:
       case MARKUP:
       case CREATE_SESSION_SECRET:
@@ -375,6 +377,10 @@ public class TobagoConfigParser extends TobagoConfigEntityResolver {
         tobagoConfig.setThemeCookie(text);
         break;
 
+      case THEME_SESSION:
+        tobagoConfig.setThemeSession(text);
+        break;
+
       case CREATE_SESSION_SECRET:
         tobagoConfig.setCreateSessionSecret(text);
         break;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
index c108680..3274cf0 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
@@ -34,7 +34,6 @@ import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
 import org.apache.myfaces.tobago.internal.component.AbstractUIScript;
 import org.apache.myfaces.tobago.internal.component.AbstractUIStyle;
 import org.apache.myfaces.tobago.internal.util.AccessKeyLogger;
-import org.apache.myfaces.tobago.internal.util.CookieUtils;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
 import org.apache.myfaces.tobago.internal.util.ResponseUtils;
 import org.apache.myfaces.tobago.internal.util.StringUtils;
@@ -61,8 +60,6 @@ import javax.faces.component.UIOutput;
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
@@ -141,10 +138,6 @@ public class PageRenderer<T extends AbstractUIPage> extends RendererBase<T> {
     }
 
     final Theme theme = tobagoContext.getTheme();
-    if (response instanceof HttpServletResponse && request instanceof HttpServletRequest
-      && tobagoConfig.isThemeCookie()) {
-      CookieUtils.setThemeNameToCookie((HttpServletRequest) request, (HttpServletResponse) response, theme.getName());
-    }
 
     final String clientId = component.getClientId(facesContext);
     final boolean productionMode = facesContext.isProjectStage(ProjectStage.Production);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/CookieUtils.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/CookieUtils.java
index bee602a..3694cc9 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/CookieUtils.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/CookieUtils.java
@@ -19,6 +19,7 @@
 
 package org.apache.myfaces.tobago.internal.util;
 
+import org.apache.myfaces.tobago.context.Theme;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,8 +32,6 @@ public class CookieUtils {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-  private static final String THEME_PARAMETER = "tobago.theme";
-
   private static final int ONE_YEAR_IN_SECONDS = 365 * 24 * 60 * 60;
 
   private CookieUtils() {
@@ -48,10 +47,10 @@ public class CookieUtils {
           LOG.debug("cookie value ='{}'", cookie.getValue());
           LOG.debug("cookie path  ='{}'", cookie.getPath());
         }
-        if (THEME_PARAMETER.equals(cookie.getName())) {
+        if (Theme.THEME_KEY.equals(cookie.getName())) {
           themeName = cookie.getValue();
           if (LOG.isDebugEnabled()) {
-            LOG.debug("theme from cookie {}='{}'", THEME_PARAMETER, themeName);
+            LOG.debug("theme from cookie {}='{}'", Theme.THEME_KEY, themeName);
           }
           break;
         }
@@ -69,10 +68,10 @@ public class CookieUtils {
     final Cookie[] cookies = request.getCookies();
     if (cookies != null) {
       for (final Cookie cookie : cookies) {
-        if (THEME_PARAMETER.equals(cookie.getName())) {
+        if (Theme.THEME_KEY.equals(cookie.getName())) {
           if (found) {
             if (LOG.isDebugEnabled()) {
-              LOG.debug("Found more than one cookie {}, try to remove them...", THEME_PARAMETER);
+              LOG.debug("Found more than one cookie {}, try to remove them...", Theme.THEME_KEY);
             }
             cookie.setMaxAge(0);
           } else {
@@ -97,7 +96,7 @@ public class CookieUtils {
       }
     }
     if (!found) {
-      final Cookie cookie = new Cookie(THEME_PARAMETER, themeName);
+      final Cookie cookie = new Cookie(Theme.THEME_KEY, themeName);
       cookie.setPath(path);
       cookie.setMaxAge(ONE_YEAR_IN_SECONDS);
       cookie.setSecure(request.isSecure());
@@ -111,7 +110,7 @@ public class CookieUtils {
     final Cookie[] cookies = request.getCookies();
     if (cookies != null) {
       for (final Cookie cookie : cookies) {
-        if (THEME_PARAMETER.equals(cookie.getName())) {
+        if (Theme.THEME_KEY.equals(cookie.getName())) {
           cookie.setMaxAge(0);
           cookie.setValue(null);
           cookie.setSecure(request.isSecure());
diff --git a/tobago-core/src/main/resources/org/apache/myfaces/tobago/config/tobago-config-5.1.xsd b/tobago-core/src/main/resources/org/apache/myfaces/tobago/config/tobago-config-5.1.xsd
index 6b45ea9..7724ea3 100644
--- a/tobago-core/src/main/resources/org/apache/myfaces/tobago/config/tobago-config-5.1.xsd
+++ b/tobago-core/src/main/resources/org/apache/myfaces/tobago/config/tobago-config-5.1.xsd
@@ -239,6 +239,13 @@
           </xs:documentation>
         </xs:annotation>
       </xs:element>
+      <xs:element name="theme-session" type="xs:boolean" minOccurs="0" maxOccurs="1" default="false">
+        <xs:annotation>
+          <xs:documentation>
+            Store the active theme the server session.
+          </xs:documentation>
+        </xs:annotation>
+      </xs:element>
     </xs:sequence>
   </xs:complexType>
 
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java
index 296adff..33e08dd 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigParserUnitTest.java
@@ -197,4 +197,20 @@ public class TobagoConfigParserUnitTest {
     Assertions.assertFalse(fragment.getThemeCookie());
   }
 
+  @Test
+  public void testThemeSessionUndefined() throws Exception {
+    final URL url = getClass().getClassLoader().getResource("tobago-config-5.0.xml");
+    final TobagoConfigParser parser = new TobagoConfigParser();
+    final TobagoConfigFragment fragment = parser.parse(url);
+    Assertions.assertNull(fragment.getThemeSession());
+  }
+
+  @Test
+  public void testThemeSessionTrue() throws Exception {
+    final URL url = getClass().getClassLoader().getResource("tobago-config-5.1.xml");
+    final TobagoConfigParser parser = new TobagoConfigParser();
+    final TobagoConfigFragment fragment = parser.parse(url);
+    Assertions.assertTrue(fragment.getThemeSession());
+  }
+
 }
diff --git a/tobago-core/src/test/resources/tobago-config-5.1.xml b/tobago-core/src/test/resources/tobago-config-5.1.xml
index 8f61e22..8ba26ba 100644
--- a/tobago-core/src/test/resources/tobago-config-5.1.xml
+++ b/tobago-core/src/test/resources/tobago-config-5.1.xml
@@ -39,6 +39,7 @@
     <default-theme>my-theme-1</default-theme>
     <supported-theme>my-theme-2</supported-theme>
     <theme-cookie>false</theme-cookie>
+    <theme-session>true</theme-session>
   </theme-config>
 
   <create-session-secret>false</create-session-secret>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/WEB-INF/tobago-config.xml b/tobago-example/tobago-example-demo/src/main/webapp/WEB-INF/tobago-config.xml
index 7ce43c6..0f0c025 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/WEB-INF/tobago-config.xml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/WEB-INF/tobago-config.xml
@@ -42,6 +42,8 @@
     <supported-theme>speyside</supported-theme>
     <supported-theme>roxborough</supported-theme>
     <supported-theme>charlotteville</supported-theme>
+    <theme-cookie>false</theme-cookie>
+    <theme-session>true</theme-session>
   </theme-config>
 
   <!-- currently you need to switch this check off for quarkus -->