or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auto-configuration.mdheader-theme-resolution.mdindex.mdservice-theme-resolution.mdtheme-resolution.mdtheme-sources.md

theme-resolution.mddocs/

0

# Theme Resolution

1

2

Chain-based theme resolution system that evaluates multiple resolution strategies in priority order to determine the appropriate theme for each request.

3

4

## Capabilities

5

6

### ChainingThemeResolver

7

8

Theme resolver that chains multiple resolvers and returns the first non-default result.

9

10

```java { .api }

11

/**

12

* Theme resolver that chains multiple resolvers using chain of responsibility pattern

13

*/

14

public class ChainingThemeResolver extends AbstractThemeResolver {

15

16

/**

17

* Default constructor creating empty resolver chain

18

*/

19

public ChainingThemeResolver();

20

21

/**

22

* Adds resolver to the chain for evaluation

23

* @param r Theme resolver to add to the chain

24

* @return This ChainingThemeResolver for method chaining

25

*/

26

@CanIgnoreReturnValue

27

public ChainingThemeResolver addResolver(ThemeResolver r);

28

29

/**

30

* Resolves theme name by trying each resolver in chain order

31

* @param httpServletRequest HTTP request to resolve theme for

32

* @return Theme name from first resolver returning non-default result, or default theme

33

*/

34

@Override

35

public String resolveThemeName(@Nonnull HttpServletRequest httpServletRequest);

36

37

/**

38

* No-op implementation for theme setting - theme is resolved, not set

39

* @param httpServletRequest HTTP request

40

* @param httpServletResponse HTTP response

41

* @param s Theme name

42

*/

43

@Override

44

public void setThemeName(@Nonnull HttpServletRequest httpServletRequest,

45

HttpServletResponse httpServletResponse, String s);

46

}

47

```

48

49

**Usage Examples:**

50

51

```java

52

import org.apereo.cas.services.web.ChainingThemeResolver;

53

import org.springframework.web.servlet.theme.CookieThemeResolver;

54

import org.springframework.web.servlet.theme.SessionThemeResolver;

55

import org.springframework.web.servlet.theme.FixedThemeResolver;

56

57

// Create chaining resolver

58

ChainingThemeResolver chainResolver = new ChainingThemeResolver();

59

chainResolver.setDefaultThemeName("default");

60

61

// Add resolvers in priority order

62

CookieThemeResolver cookieResolver = new CookieThemeResolver();

63

cookieResolver.setDefaultThemeName("default");

64

chainResolver.addResolver(cookieResolver);

65

66

SessionThemeResolver sessionResolver = new SessionThemeResolver();

67

sessionResolver.setDefaultThemeName("default");

68

chainResolver.addResolver(sessionResolver);

69

70

FixedThemeResolver fixedResolver = new FixedThemeResolver();

71

fixedResolver.setDefaultThemeName("default");

72

chainResolver.addResolver(fixedResolver);

73

74

// Resolve theme for request

75

String themeName = chainResolver.resolveThemeName(request);

76

```

77

78

## Resolution Chain Strategy

79

80

The ChainingThemeResolver evaluates resolvers in the order they were added:

81

82

1. **First Match Wins**: Returns theme from first resolver that returns non-default theme

83

2. **Skip Default**: Continues chain if resolver returns the configured default theme name

84

3. **Final Fallback**: Returns default theme if no resolver provides a specific theme

85

86

```java

87

// Example evaluation flow:

88

// 1. CookieThemeResolver returns "default" -> continue

89

// 2. SessionThemeResolver returns "dark" -> return "dark"

90

// 3. Remaining resolvers are not evaluated

91

```

92

93

## Standard Resolution Chain

94

95

A typical CAS theme resolution chain includes:

96

97

1. **Cookie Theme Resolver** - Highest priority, user preference persistence

98

2. **Session Theme Resolver** - Session-scoped theme selection

99

3. **Request Header Theme Resolver** - API-driven theme selection

100

4. **Registered Service Theme Resolver** - Service-specific themes

101

5. **Fixed Theme Resolver** - Default fallback theme

102

103

```java

104

// Standard chain configuration (as done by auto-configuration)

105

chainResolver

106

.addResolver(cookieThemeResolver) // Priority 1

107

.addResolver(sessionThemeResolver) // Priority 2

108

.addResolver(headerThemeResolver) // Priority 3

109

.addResolver(serviceThemeResolver) // Priority 4

110

.addResolver(fixedThemeResolver); // Priority 5 (fallback)

111

```

112

113

## Theme Resolution Behavior

114

115

### Default Theme Handling

116

117

- Each resolver has a configured `defaultThemeName`

118

- Chain continues evaluation when resolver returns default theme

119

- Final fallback is the chain's own default theme

120

121

### Theme Name Validation

122

123

- No built-in theme name validation

124

- Theme names are passed through as-is

125

- Theme existence validation happens at theme source level

126

127

### Request Context

128

129

Theme resolution occurs within the context of:

130

- HTTP servlet request

131

- Spring Web MVC request cycle

132

- CAS authentication flow

133

- Service-specific processing

134

135

## Error Handling

136

137

The chaining resolver provides robust error handling:

138

139

- **Resolver Exceptions**: Logged and chain continues with next resolver

140

- **Null Results**: Treated as default theme, chain continues

141

- **Empty Strings**: Treated as default theme, chain continues

142

- **Chain Exhaustion**: Returns configured default theme

143

144

## Performance Considerations

145

146

- **Lazy Evaluation**: Resolvers evaluated only until first match

147

- **Ordered Execution**: Place fastest/most-likely resolvers first

148

- **Caching**: Individual resolvers may implement caching

149

- **Request Scoped**: Resolution happens per-request, not cached across requests

150

151

## Custom Resolver Integration

152

153

```java

154

// Example custom resolver

155

public class DatabaseThemeResolver extends AbstractThemeResolver {

156

@Override

157

public String resolveThemeName(HttpServletRequest request) {

158

String userId = getUserIdFromRequest(request);

159

return userThemeService.getThemeForUser(userId);

160

}

161

162

@Override

163

public void setThemeName(HttpServletRequest request,

164

HttpServletResponse response, String themeName) {

165

// Implement theme persistence if needed

166

}

167

}

168

169

// Add to chain

170

DatabaseThemeResolver dbResolver = new DatabaseThemeResolver();

171

dbResolver.setDefaultThemeName("default");

172

chainResolver.addResolver(dbResolver);

173

```