0
# Theme Sources
1
2
Theme source implementations that load and manage theme properties and resources from various locations.
3
4
## Capabilities
5
6
### DefaultCasThemeSource
7
8
Default theme source implementation that searches template prefixes for theme properties and supports hierarchical theme inheritance.
9
10
```java { .api }
11
/**
12
* Default theme source that extends ResourceBundleThemeSource with CAS-specific features
13
*/
14
public class DefaultCasThemeSource extends ResourceBundleThemeSource {
15
16
/**
17
* Constructor requiring CAS configuration properties
18
* @param casProperties CAS configuration containing template prefixes and theme settings
19
*/
20
public DefaultCasThemeSource(CasConfigurationProperties casProperties);
21
22
/**
23
* Creates message source for theme properties, searches template prefixes first
24
* @param basename Theme base name (e.g., "default", "custom")
25
* @return MessageSource containing theme properties and messages
26
*/
27
@Nonnull
28
@Override
29
protected MessageSource createMessageSource(@Nonnull String basename);
30
31
/**
32
* Creates hierarchical message source with custom and default theme support
33
* @param basename Theme base name
34
* @return MessageSource with parent-child hierarchy
35
*/
36
protected MessageSource createExtendedMessageSource(String basename);
37
38
/**
39
* Loads properties from specified path and creates static message source
40
* @param path Path to theme properties file
41
* @return StaticMessageSource with loaded properties
42
* @throws Exception if resource cannot be loaded
43
*/
44
protected StaticMessageSource loadMessageSourceFromPath(String path) throws Exception;
45
}
46
```
47
48
**Usage Examples:**
49
50
```java
51
import org.apereo.cas.services.web.DefaultCasThemeSource;
52
import org.apereo.cas.configuration.CasConfigurationProperties;
53
54
// Create default theme source
55
CasConfigurationProperties properties = // ... configured instance
56
DefaultCasThemeSource themeSource = new DefaultCasThemeSource(properties);
57
58
// Theme source will search for properties in configured template prefixes:
59
// /etc/cas/themes/mytheme.properties
60
// classpath:/themes/mytheme.properties
61
// Standard resource bundle locations
62
```
63
64
### AggregateCasThemeSource
65
66
Theme source that merges all theme resource bundles it can find across all configured template prefixes.
67
68
```java { .api }
69
/**
70
* Theme source that aggregates properties from multiple theme resource bundles
71
*/
72
public class AggregateCasThemeSource extends ResourceBundleThemeSource {
73
74
/**
75
* Constructor requiring CAS configuration properties
76
* @param casProperties CAS configuration containing template prefixes
77
*/
78
public AggregateCasThemeSource(CasConfigurationProperties casProperties);
79
80
/**
81
* Creates message source that aggregates properties from all template prefixes
82
* @param basename Theme base name to search for across all prefixes
83
* @return MessageSource containing merged properties from all found resources
84
*/
85
@Nonnull
86
@Override
87
protected MessageSource createMessageSource(@Nonnull String basename);
88
}
89
```
90
91
**Usage Examples:**
92
93
```java
94
import org.apereo.cas.services.web.AggregateCasThemeSource;
95
96
// Create aggregate theme source
97
AggregateCasThemeSource themeSource = new AggregateCasThemeSource(properties);
98
99
// Will merge properties from all matching files:
100
// /etc/cas/themes/mytheme.properties
101
// /var/cas/themes/mytheme.properties
102
// classpath:/themes/mytheme.properties
103
// All properties are combined into single MessageSource
104
```
105
106
### CasThemeResourceBundleMessageSource
107
108
Enhanced message source for theme resource bundles with improved error handling and validation.
109
110
```java { .api }
111
/**
112
* Custom message source for theme resource bundles with enhanced error handling
113
* Validates that resource bundles are not empty before returning them
114
*/
115
public class CasThemeResourceBundleMessageSource extends ResourceBundleMessageSource {
116
117
/**
118
* Gets resource bundle with null-safe error handling and validation
119
* Returns null if bundle is not found, empty, or an exception occurs
120
* @param basename Base name of the resource bundle
121
* @param locale Locale for the bundle
122
* @return ResourceBundle if found and non-empty, null otherwise for graceful fallback
123
*/
124
@Override
125
protected ResourceBundle doGetBundle(String basename, Locale locale);
126
}
127
```
128
129
**Usage Examples:**
130
131
```java
132
import org.apereo.cas.services.web.CasThemeResourceBundleMessageSource;
133
134
// Create enhanced message source for theme validation
135
CasThemeResourceBundleMessageSource messageSource = new CasThemeResourceBundleMessageSource();
136
messageSource.setBasename("mytheme");
137
138
// The message source will validate bundle existence and content
139
// Returns null for missing or empty bundles, allowing graceful fallback
140
ResourceBundle bundle = messageSource.doGetBundle("mytheme", Locale.ENGLISH);
141
if (bundle != null) {
142
// Bundle exists and has content
143
String message = bundle.getString("login.welcome");
144
}
145
```
146
147
## Theme Property File Format
148
149
Theme properties files use standard Java properties format:
150
151
```properties
152
# Theme metadata
153
theme.name=My Custom Theme
154
theme.description=A beautiful custom theme for CAS
155
156
# CSS and JavaScript resources
157
theme.css.file=css/custom.css
158
theme.js.file=js/custom.js
159
160
# Localized messages
161
login.welcome=Welcome to CAS
162
login.instructions=Please enter your credentials
163
error.authentication.failed=Authentication failed
164
```
165
166
## Theme Search Strategy
167
168
### DefaultCasThemeSource Search Order
169
170
1. **Template Prefixes**: Searches configured template prefixes in order
171
- Example: `/etc/cas/themes/mytheme.properties`
172
- Example: `classpath:/themes/mytheme.properties`
173
174
2. **Hierarchical Support**: Creates parent-child message source hierarchy
175
- Custom theme inherits from default theme
176
- Replaces `-default` with `-custom` in basename
177
178
3. **Fallback**: Uses standard ResourceBundle mechanism if not found in prefixes
179
180
### AggregateCasThemeSource Merging
181
182
1. **Collect All**: Finds all matching property files across all template prefixes
183
2. **Merge Properties**: Combines all properties into single MessageSource
184
3. **Parent Chain**: Sets standard ResourceBundle as parent for fallback
185
186
## Resource Loading
187
188
Both theme sources support loading from:
189
190
- **File System**: `file:/path/to/themes/`
191
- **Classpath**: `classpath:/themes/`
192
- **HTTP URLs**: `http://example.com/themes/` (via ResourceUtils)
193
- **Custom Resources**: Any Spring Resource implementation
194
195
```java
196
// Example template prefix configurations
197
cas.view.template-prefixes[0]=file:/etc/cas/themes/
198
cas.view.template-prefixes[1]=classpath:/themes/
199
cas.view.template-prefixes[2]=http://cdn.example.com/cas-themes/
200
```
201
202
## Locale Support
203
204
Theme sources support internationalization:
205
206
```java
207
// DefaultCasThemeSource loads properties for multiple locales
208
List.of(Locale.US, Locale.CANADA, Locale.ENGLISH).forEach(locale -> {
209
source.addMessage(key.toString(), locale, value.toString());
210
});
211
212
// AggregateCasThemeSource uses English locale by default
213
source.addMessage(key.toString(), Locale.ENGLISH, value.toString());
214
```
215
216
## Error Handling
217
218
- **Resource Not Found**: Gracefully falls back to parent message sources
219
- **IO Exceptions**: Logged as warnings, theme loading continues
220
- **Invalid Properties**: Individual property errors don't stop theme loading
221
- **Bundle Validation**: CasThemeResourceBundleMessageSource validates bundle contents