0
# Utility Libraries
1
2
Play Framework provides a comprehensive collection of utility libraries for common web development tasks including cryptographic operations, time parsing, XML/YAML processing, classpath scanning, and content type handling. These utilities are designed for high-performance web applications with security and ease of use in mind.
3
4
## Capabilities
5
6
### Cryptographic Utilities
7
8
Comprehensive cryptographic operations including signing, token generation, and AES encryption with application-level key management.
9
10
```java { .api }
11
/**
12
* Cryptographic utilities for signing, encryption, and secure token generation
13
*/
14
public class Crypto {
15
/** Sign message with provided key */
16
public String sign(String message, byte[] key);
17
18
/** Sign message with application secret key */
19
public String sign(String message);
20
21
/** Sign token with timestamp nonce for replay protection */
22
public String signToken(String token);
23
24
/** Extract and verify signed token */
25
public String extractSignedToken(String token);
26
27
/** Generate cryptographically secure random token */
28
public String generateToken();
29
30
/** Generate signed secure token */
31
public String generateSignedToken();
32
33
/** Compare signed tokens in constant time */
34
public boolean compareSignedTokens(String tokenA, String tokenB);
35
36
/** Constant time string comparison to prevent timing attacks */
37
public boolean constantTimeEquals(String a, String b);
38
39
/** AES encrypt with application secret key */
40
public String encryptAES(String value);
41
42
/** AES encrypt with specific private key */
43
public String encryptAES(String value, String privateKey);
44
45
/** AES decrypt with application secret key */
46
public String decryptAES(String value);
47
48
/** AES decrypt with specific private key */
49
public String decryptAES(String value, String privateKey);
50
}
51
```
52
53
**Usage Examples:**
54
55
```java
56
import play.libs.Crypto;
57
58
// Token generation and signing
59
public class AuthService {
60
61
public String createSessionToken(String userId) {
62
String token = Crypto.generateToken();
63
String signedToken = Crypto.signToken(userId + ":" + token);
64
return signedToken;
65
}
66
67
public String validateSessionToken(String signedToken) {
68
try {
69
String extracted = Crypto.extractSignedToken(signedToken);
70
String[] parts = extracted.split(":");
71
return parts[0]; // Return userId
72
} catch (Exception e) {
73
return null; // Invalid token
74
}
75
}
76
77
public String encryptSensitiveData(String data) {
78
return Crypto.encryptAES(data);
79
}
80
81
public String decryptSensitiveData(String encryptedData) {
82
return Crypto.decryptAES(encryptedData);
83
}
84
}
85
86
// CSRF protection
87
public class CSRFService {
88
89
public String generateCSRFToken() {
90
return Crypto.generateSignedToken();
91
}
92
93
public boolean validateCSRFToken(String token, String expected) {
94
return Crypto.compareSignedTokens(token, expected);
95
}
96
}
97
```
98
99
### Time and Scheduling Utilities
100
101
Comprehensive time parsing utilities including duration parsing and CRON expression handling for scheduling and time-based operations.
102
103
```java { .api }
104
/**
105
* Time utilities for duration parsing and CRON expression handling
106
*/
107
public class Time {
108
/** Parse duration string to seconds (e.g., "3h", "2mn", "45s") */
109
public static int parseDuration(String duration);
110
111
/** Parse CRON expression to next execution date */
112
public static Date parseCRONExpression(String cron);
113
114
/** Get interval in milliseconds to next CRON execution */
115
public static long cronInterval(String cron);
116
117
/** Get interval in milliseconds to next CRON execution from specific date */
118
public static long cronInterval(String cron, Date date);
119
}
120
121
/**
122
* CRON expression parser and evaluator with timezone support
123
*/
124
public static class Time.CronExpression implements Serializable, Cloneable {
125
/** Create CRON expression from string */
126
public CronExpression(String cronExpression) throws ParseException;
127
128
/** Check if date satisfies CRON expression */
129
public boolean isSatisfiedBy(Date date);
130
131
/** Get next valid execution time after given date */
132
public Date getNextValidTimeAfter(Date date);
133
134
/** Get next invalid time after given date */
135
public Date getNextInvalidTimeAfter(Date date);
136
137
/** Get interval in milliseconds to next occurrence */
138
public long getNextInterval(Date date);
139
140
/** Get timezone for this expression */
141
public TimeZone getTimeZone();
142
143
/** Set timezone for this expression */
144
public void setTimeZone(TimeZone timeZone);
145
146
/** Validate CRON expression string */
147
public static boolean isValidExpression(String cronExpression);
148
}
149
```
150
151
**Usage Examples:**
152
153
```java
154
import play.libs.Time;
155
import play.libs.Time.CronExpression;
156
157
// Duration parsing
158
public class SchedulingService {
159
160
public void scheduleTask(String durationStr, Runnable task) {
161
int seconds = Time.parseDuration(durationStr);
162
scheduler.schedule(task, seconds, TimeUnit.SECONDS);
163
164
// Examples:
165
// "1h" -> 3600 seconds
166
// "30mn" -> 1800 seconds
167
// "45s" -> 45 seconds
168
// "2d" -> 172800 seconds
169
}
170
}
171
172
// CRON expression handling
173
public class CronScheduler {
174
175
public void scheduleJob(String cronExpression, Runnable job) {
176
try {
177
CronExpression cron = new CronExpression(cronExpression);
178
179
// Schedule next execution
180
Date nextRun = cron.getNextValidTimeAfter(new Date());
181
long delay = nextRun.getTime() - System.currentTimeMillis();
182
183
scheduler.schedule(() -> {
184
job.run();
185
// Reschedule for next occurrence
186
scheduleJob(cronExpression, job);
187
}, delay, TimeUnit.MILLISECONDS);
188
189
} catch (ParseException e) {
190
Logger.error("Invalid CRON expression: " + cronExpression, e);
191
}
192
}
193
194
public boolean isValidCron(String expression) {
195
return CronExpression.isValidExpression(expression);
196
}
197
}
198
199
// Examples of CRON expressions:
200
// "0 0 12 * * ?" -> Daily at noon
201
// "0 15 10 ? * MON-FRI" -> Weekdays at 10:15 AM
202
// "0 0/5 * * * ?" -> Every 5 minutes
203
```
204
205
### XML Processing Utilities
206
207
XPath-based XML processing utilities with namespace support for parsing and extracting data from XML documents.
208
209
```java { .api }
210
/**
211
* XPath parsing utilities with namespace support
212
*/
213
public class XPath {
214
/** Select multiple nodes using XPath with namespaces */
215
public static NodeList selectNodes(String path, Object node, Map<String, String> namespaces);
216
217
/** Select multiple nodes using XPath without namespaces */
218
public static NodeList selectNodes(String path, Object node);
219
220
/** Select single node using XPath with namespaces */
221
public static Node selectNode(String path, Object node, Map<String, String> namespaces);
222
223
/** Select single node using XPath without namespaces */
224
public static Node selectNode(String path, Object node);
225
226
/** Get text content using XPath with namespaces */
227
public static String selectText(String path, Object node, Map<String, String> namespaces);
228
229
/** Get text content using XPath without namespaces */
230
public static String selectText(String path, Object node);
231
}
232
```
233
234
**Usage Examples:**
235
236
```java
237
import play.libs.XPath;
238
import org.w3c.dom.Document;
239
import org.w3c.dom.Node;
240
import org.w3c.dom.NodeList;
241
242
// XML parsing service
243
public class XMLService {
244
245
public List<String> extractUserNames(Document xmlDoc) {
246
NodeList userNodes = XPath.selectNodes("//user/name", xmlDoc);
247
List<String> names = new ArrayList<>();
248
249
for (int i = 0; i < userNodes.getLength(); i++) {
250
names.add(userNodes.item(i).getTextContent());
251
}
252
253
return names;
254
}
255
256
public String extractConfigValue(Document config, String key) {
257
String xpath = "//config/setting[@name='" + key + "']/@value";
258
return XPath.selectText(xpath, config);
259
}
260
261
public Map<String, String> extractNamespacedData(Document xmlDoc) {
262
Map<String, String> namespaces = new HashMap<>();
263
namespaces.put("ns", "http://example.com/namespace");
264
265
NodeList items = XPath.selectNodes("//ns:item", xmlDoc, namespaces);
266
Map<String, String> data = new HashMap<>();
267
268
for (int i = 0; i < items.getLength(); i++) {
269
Node item = items.item(i);
270
String id = XPath.selectText("@id", item);
271
String value = XPath.selectText("ns:value", item, namespaces);
272
data.put(id, value);
273
}
274
275
return data;
276
}
277
}
278
```
279
280
### YAML Processing Utilities
281
282
YAML parsing utilities for configuration files and data serialization with classpath resource support.
283
284
```java { .api }
285
/**
286
* YAML parsing utilities for configuration and data files
287
*/
288
public class Yaml {
289
/** Load YAML from classpath resource */
290
public static Object load(String resourceName);
291
292
/** Load YAML from input stream with specific classloader */
293
public static Object load(InputStream is, ClassLoader classloader);
294
}
295
```
296
297
**Usage Examples:**
298
299
```java
300
import play.libs.Yaml;
301
302
// Configuration loading
303
public class ConfigService {
304
305
@SuppressWarnings("unchecked")
306
public Map<String, Object> loadConfig(String configFile) {
307
Object config = Yaml.load(configFile);
308
if (config instanceof Map) {
309
return (Map<String, Object>) config;
310
}
311
throw new IllegalArgumentException("Config file is not a valid YAML map");
312
}
313
314
public DatabaseConfig loadDatabaseConfig() {
315
Map<String, Object> config = loadConfig("database.yml");
316
317
return new DatabaseConfig(
318
(String) config.get("url"),
319
(String) config.get("username"),
320
(String) config.get("password")
321
);
322
}
323
}
324
325
// Test data loading
326
public class TestDataLoader {
327
328
@SuppressWarnings("unchecked")
329
public List<User> loadTestUsers() {
330
Object data = Yaml.load("test-users.yml");
331
List<Map<String, Object>> userMaps = (List<Map<String, Object>>) data;
332
333
return userMaps.stream()
334
.map(this::mapToUser)
335
.collect(Collectors.toList());
336
}
337
338
private User mapToUser(Map<String, Object> userMap) {
339
User user = new User();
340
user.name = (String) userMap.get("name");
341
user.email = (String) userMap.get("email");
342
user.age = (Integer) userMap.get("age");
343
return user;
344
}
345
}
346
```
347
348
### Classpath Utilities
349
350
Comprehensive classpath scanning utilities for type discovery and annotation-based component scanning.
351
352
```java { .api }
353
/**
354
* Classpath scanning utilities for type discovery and reflection
355
*/
356
public class Classpath {
357
/** Scan types in package using Application context */
358
public static Set<String> getTypes(Application app, String packageName);
359
360
/** Find types annotated with specific annotation using Application */
361
public static Set<Class<?>> getTypesAnnotatedWith(Application app, String packageName, Class<? extends Annotation> annotation);
362
363
/** Scan types in package using Environment */
364
public static Set<String> getTypes(Environment env, String packageName);
365
366
/** Find types annotated with specific annotation using Environment */
367
public static Set<Class<?>> getTypesAnnotatedWith(Environment env, String packageName, Class<? extends Annotation> annotation);
368
369
/** Create Reflections configuration for package scanning */
370
public static ConfigurationBuilder getReflectionsConfiguration(String packageName, ClassLoader classLoader);
371
}
372
```
373
374
**Usage Examples:**
375
376
```java
377
import play.libs.Classpath;
378
import play.Application;
379
380
// Component scanning service
381
public class ComponentScanner {
382
383
public Set<Class<?>> findControllers(Application app) {
384
return Classpath.getTypesAnnotatedWith(app, "controllers", Controller.class);
385
}
386
387
public Set<Class<?>> findServices(Application app) {
388
return Classpath.getTypesAnnotatedWith(app, "services", Service.class);
389
}
390
391
public Set<Class<?>> findRepositories(Application app) {
392
return Classpath.getTypesAnnotatedWith(app, "repositories", Repository.class);
393
}
394
}
395
396
// Auto-registration service
397
public class AutoRegistrationService {
398
399
public void autoRegisterComponents(Application app, Injector injector) {
400
// Find all classes annotated with @Component
401
Set<Class<?>> components = Classpath.getTypesAnnotatedWith(
402
app, "com.myapp", Component.class);
403
404
for (Class<?> componentClass : components) {
405
try {
406
Object instance = injector.getInstance(componentClass);
407
// Register component in some registry
408
componentRegistry.register(componentClass, instance);
409
} catch (Exception e) {
410
Logger.warn("Failed to register component: " + componentClass, e);
411
}
412
}
413
}
414
}
415
416
// Plugin discovery
417
public class PluginDiscovery {
418
419
public List<Plugin> discoverPlugins(Application app) {
420
Set<Class<?>> pluginClasses = Classpath.getTypesAnnotatedWith(
421
app, "plugins", PluginMarker.class);
422
423
return pluginClasses.stream()
424
.filter(Plugin.class::isAssignableFrom)
425
.map(clazz -> {
426
try {
427
return (Plugin) clazz.newInstance();
428
} catch (Exception e) {
429
Logger.error("Failed to instantiate plugin: " + clazz, e);
430
return null;
431
}
432
})
433
.filter(Objects::nonNull)
434
.collect(Collectors.toList());
435
}
436
}
437
```
438
439
### JSONP Content Utilities
440
441
JSONP content rendering utilities for cross-domain JavaScript communication.
442
443
```java { .api }
444
/**
445
* JSONP content renderer for cross-domain JavaScript responses
446
*/
447
public class Jsonp implements Content {
448
/** Create JSONP response with callback and JSON data */
449
public Jsonp(String padding, JsonNode json);
450
451
/** Get response body */
452
public String body();
453
454
/** Get content type */
455
public String contentType();
456
457
/** Create JSONP content with callback function */
458
public static Jsonp jsonp(String padding, JsonNode json);
459
}
460
```
461
462
**Usage Examples:**
463
464
```java
465
import play.libs.Jsonp;
466
import play.libs.Json;
467
468
// JSONP API controller
469
public class JsonpController extends Controller {
470
471
public Result getUsersJsonp(String callback) {
472
List<User> users = userService.getAllUsers();
473
JsonNode usersJson = Json.toJson(users);
474
475
// Create JSONP response
476
Jsonp jsonpContent = Jsonp.jsonp(callback, usersJson);
477
return ok(jsonpContent);
478
}
479
480
public Result getDataJsonp() {
481
String callback = request().getQueryString("callback");
482
if (callback == null) {
483
callback = "callback"; // Default callback name
484
}
485
486
Map<String, Object> data = new HashMap<>();
487
data.put("status", "success");
488
data.put("timestamp", new Date());
489
data.put("data", getData());
490
491
JsonNode dataJson = Json.toJson(data);
492
return ok(Jsonp.jsonp(callback, dataJson));
493
}
494
}
495
```
496
497
## Advanced Usage Patterns
498
499
### Secure Token Management
500
501
```java
502
// Comprehensive token service
503
public class TokenService {
504
505
private static final long TOKEN_VALIDITY = 3600000; // 1 hour
506
507
public String createAccessToken(String userId) {
508
long expiry = System.currentTimeMillis() + TOKEN_VALIDITY;
509
String tokenData = userId + ":" + expiry;
510
return Crypto.signToken(Base64.getEncoder().encodeToString(tokenData.getBytes()));
511
}
512
513
public String validateAccessToken(String token) {
514
try {
515
String extracted = Crypto.extractSignedToken(token);
516
String tokenData = new String(Base64.getDecoder().decode(extracted));
517
String[] parts = tokenData.split(":");
518
519
String userId = parts[0];
520
long expiry = Long.parseLong(parts[1]);
521
522
if (System.currentTimeMillis() > expiry) {
523
return null; // Token expired
524
}
525
526
return userId;
527
} catch (Exception e) {
528
return null; // Invalid token
529
}
530
}
531
532
public String createRefreshToken(String userId) {
533
String tokenData = userId + ":" + Crypto.generateToken();
534
return Crypto.encryptAES(tokenData);
535
}
536
537
public String validateRefreshToken(String refreshToken) {
538
try {
539
String decrypted = Crypto.decryptAES(refreshToken);
540
String[] parts = decrypted.split(":");
541
return parts[0]; // Return userId
542
} catch (Exception e) {
543
return null; // Invalid refresh token
544
}
545
}
546
}
547
```
548
549
### Configuration Management
550
551
```java
552
// Advanced configuration service using multiple sources
553
public class ConfigurationManager {
554
555
private final Map<String, Object> configuration = new HashMap<>();
556
557
public ConfigurationManager() {
558
loadFromYaml();
559
loadFromEnvironment();
560
loadFromSystemProperties();
561
}
562
563
private void loadFromYaml() {
564
try {
565
Object yamlConfig = Yaml.load("application.yml");
566
if (yamlConfig instanceof Map) {
567
configuration.putAll((Map<String, Object>) yamlConfig);
568
}
569
} catch (Exception e) {
570
Logger.warn("Failed to load YAML configuration", e);
571
}
572
}
573
574
private void loadFromEnvironment() {
575
System.getenv().forEach((key, value) -> {
576
if (key.startsWith("APP_")) {
577
String configKey = key.toLowerCase().replace("app_", "").replace("_", ".");
578
configuration.put(configKey, value);
579
}
580
});
581
}
582
583
private void loadFromSystemProperties() {
584
System.getProperties().forEach((key, value) -> {
585
if (key.toString().startsWith("app.")) {
586
configuration.put(key.toString(), value);
587
}
588
});
589
}
590
591
public String getString(String key, String defaultValue) {
592
return (String) configuration.getOrDefault(key, defaultValue);
593
}
594
595
public Integer getInt(String key, Integer defaultValue) {
596
Object value = configuration.get(key);
597
if (value instanceof String) {
598
return Integer.parseInt((String) value);
599
}
600
return value instanceof Integer ? (Integer) value : defaultValue;
601
}
602
}
603
```