0
# Utilities
1
2
Apache Shiro provides essential utility classes and interfaces for configuration, thread context management, lifecycle operations, and integration with various environments and frameworks. These utilities simplify common security operations and provide building blocks for custom integrations.
3
4
## Capabilities
5
6
### Security Utilities
7
8
Central utility class providing static access to core Shiro functionality.
9
10
```java { .api }
11
/**
12
* Utility class providing convenient static methods for accessing common security operations.
13
*/
14
public abstract class SecurityUtils {
15
/**
16
* Returns the currently executing Subject associated with the calling thread, or a new empty/anonymous Subject if none is associated.
17
* @return the Subject associated with the calling thread or a new empty/anonymous Subject if none is associated
18
*/
19
public static Subject getSubject();
20
21
/**
22
* Returns the SecurityManager accessible to the calling code.
23
* @return the SecurityManager accessible to the calling code
24
*/
25
public static SecurityManager getSecurityManager();
26
27
/**
28
* Sets the SecurityManager accessible to all threads.
29
* @param securityManager the SecurityManager to set
30
*/
31
public static void setSecurityManager(SecurityManager securityManager);
32
}
33
```
34
35
**Usage Examples:**
36
37
```java
38
// Get current user
39
Subject currentUser = SecurityUtils.getSubject();
40
41
// Check if user is authenticated
42
if (currentUser.isAuthenticated()) {
43
System.out.println("User is logged in");
44
}
45
46
// Get security manager
47
SecurityManager sm = SecurityUtils.getSecurityManager();
48
49
// Set security manager (typically done during application startup)
50
DefaultSecurityManager securityManager = new DefaultSecurityManager(realm);
51
SecurityUtils.setSecurityManager(securityManager);
52
```
53
54
### Thread Context Management
55
56
Utilities for managing security context in multi-threaded environments.
57
58
```java { .api }
59
/**
60
* Utility class for managing security context in thread-local storage.
61
*/
62
public final class ThreadContext {
63
/**
64
* Returns the SecurityManager bound to the current thread, or null if none is bound.
65
* @return the SecurityManager bound to the current thread, or null if none is bound
66
*/
67
public static SecurityManager getSecurityManager();
68
69
/**
70
* Binds a SecurityManager to the current thread.
71
* @param securityManager the SecurityManager to bind to the current thread
72
*/
73
public static void bind(SecurityManager securityManager);
74
75
/**
76
* Unbinds the SecurityManager from the current thread.
77
* @return the SecurityManager previously bound to the current thread, or null if none was bound
78
*/
79
public static SecurityManager unbindSecurityManager();
80
81
/**
82
* Returns the Subject bound to the current thread, or null if none is bound.
83
* @return the Subject bound to the current thread, or null if none is bound
84
*/
85
public static Subject getSubject();
86
87
/**
88
* Binds a Subject to the current thread.
89
* @param subject the Subject to bind to the current thread
90
*/
91
public static void bind(Subject subject);
92
93
/**
94
* Unbinds the Subject from the current thread.
95
* @return the Subject previously bound to the current thread, or null if none was bound
96
*/
97
public static Subject unbindSubject();
98
99
/**
100
* Returns all resources bound to the current thread.
101
* @return all resources bound to the current thread as a Map
102
*/
103
public static Map<Object, Object> getResources();
104
105
/**
106
* Returns the resource bound to the current thread under the specified key.
107
* @param key the key used to lookup the resource
108
* @return the resource bound to the current thread under the specified key
109
*/
110
public static Object get(Object key);
111
112
/**
113
* Binds a resource to the current thread under the specified key.
114
* @param key the key to bind the resource under
115
* @param value the resource to bind
116
*/
117
public static void put(Object key, Object value);
118
119
/**
120
* Unbinds the resource associated with the specified key from the current thread.
121
* @param key the key of the resource to unbind
122
* @return the resource that was unbound, or null if no resource was bound under that key
123
*/
124
public static Object remove(Object key);
125
126
/**
127
* Removes all resources bound to the current thread.
128
*/
129
public static void clear();
130
}
131
```
132
133
**Usage Examples:**
134
135
```java
136
// Manual thread context management
137
public void executeInSecurityContext(Runnable task) {
138
Subject subject = SecurityUtils.getSubject();
139
140
try {
141
// Bind current subject to new thread
142
ThreadContext.bind(subject);
143
144
// Execute task with security context
145
task.run();
146
147
} finally {
148
// Always clean up thread context
149
ThreadContext.clear();
150
}
151
}
152
153
// Custom resource binding
154
ThreadContext.put("customKey", customObject);
155
Object retrieved = ThreadContext.get("customKey");
156
ThreadContext.remove("customKey");
157
```
158
159
### Thread State Management
160
161
Interfaces and implementations for managing thread state across security contexts.
162
163
```java { .api }
164
/**
165
* Interface for managing thread state that can be backed up and restored.
166
*/
167
public interface ThreadState {
168
/**
169
* Saves the current thread state and replaces it with the state represented by this instance.
170
*/
171
void bind();
172
173
/**
174
* Completely removes the state that was previously bound.
175
*/
176
void clear();
177
178
/**
179
* Restores the original thread state that existed before this instance's state was bound.
180
*/
181
void restore();
182
}
183
184
/**
185
* ThreadState implementation that manages Subject state for the current thread.
186
*/
187
public class SubjectThreadState implements ThreadState {
188
/**
189
* Constructor accepting the Subject that should be bound to the current thread.
190
* @param subject the Subject that should be bound to the current thread
191
*/
192
public SubjectThreadState(Subject subject);
193
194
/**
195
* Returns the Subject that will be bound to the current thread.
196
* @return the Subject that will be bound to the current thread
197
*/
198
public Subject getSubject();
199
200
public void bind();
201
public void clear();
202
public void restore();
203
}
204
```
205
206
**Usage Examples:**
207
208
```java
209
// Subject-aware thread execution
210
public void executeAsSubject(Subject subject, Runnable task) {
211
SubjectThreadState threadState = new SubjectThreadState(subject);
212
213
try {
214
threadState.bind();
215
task.run();
216
} finally {
217
threadState.restore();
218
}
219
}
220
221
// Custom thread state implementation
222
public class CustomThreadState implements ThreadState {
223
private final Map<String, Object> customState;
224
private Map<Object, Object> originalResources;
225
226
public CustomThreadState(Map<String, Object> state) {
227
this.customState = state;
228
}
229
230
@Override
231
public void bind() {
232
originalResources = ThreadContext.getResources();
233
customState.forEach(ThreadContext::put);
234
}
235
236
@Override
237
public void restore() {
238
ThreadContext.clear();
239
if (originalResources != null) {
240
originalResources.forEach(ThreadContext::put);
241
}
242
}
243
244
@Override
245
public void clear() {
246
ThreadContext.clear();
247
}
248
}
249
```
250
251
### Lifecycle Management
252
253
Interfaces and utilities for component lifecycle management.
254
255
```java { .api }
256
/**
257
* Interface implemented by components that need initialization.
258
*/
259
public interface Initializable {
260
/**
261
* Initializes this instance after all properties have been set.
262
* @throws ShiroException if initialization fails
263
*/
264
void init() throws ShiroException;
265
}
266
267
/**
268
* Interface implemented by components that need cleanup when destroyed.
269
*/
270
public interface Destroyable {
271
/**
272
* Destroys this instance, releasing any resources.
273
* @throws Exception if destruction fails
274
*/
275
void destroy() throws Exception;
276
}
277
278
/**
279
* Interface implemented by components that have names.
280
*/
281
public interface Nameable {
282
/**
283
* Sets the name of this component.
284
* @param name the name to assign to this component
285
*/
286
void setName(String name);
287
288
/**
289
* Returns the name assigned to this component.
290
* @return the name assigned to this component
291
*/
292
String getName();
293
}
294
295
/**
296
* Utility class for managing component lifecycles.
297
*/
298
public final class LifecycleUtils {
299
/**
300
* Initializes the specified object if it implements Initializable.
301
* @param o the object to initialize
302
* @throws ShiroException if initialization fails
303
*/
304
public static void init(Object o) throws ShiroException;
305
306
/**
307
* Initializes all objects in the specified collection.
308
* @param c the collection of objects to initialize
309
* @throws ShiroException if initialization of any object fails
310
*/
311
public static void init(Collection c) throws ShiroException;
312
313
/**
314
* Destroys the specified object if it implements Destroyable.
315
* @param o the object to destroy
316
*/
317
public static void destroy(Object o);
318
319
/**
320
* Destroys all objects in the specified collection.
321
* @param c the collection of objects to destroy
322
*/
323
public static void destroy(Collection c);
324
}
325
```
326
327
**Usage Examples:**
328
329
```java
330
// Custom component with lifecycle
331
public class MySecurityComponent implements Initializable, Destroyable, Nameable {
332
private String name;
333
private boolean initialized = false;
334
335
@Override
336
public void init() throws ShiroException {
337
if (initialized) {
338
return;
339
}
340
341
// Perform initialization
342
setupResources();
343
validateConfiguration();
344
initialized = true;
345
346
System.out.println("Component " + name + " initialized");
347
}
348
349
@Override
350
public void destroy() throws Exception {
351
if (!initialized) {
352
return;
353
}
354
355
// Cleanup resources
356
releaseResources();
357
initialized = false;
358
359
System.out.println("Component " + name + " destroyed");
360
}
361
362
@Override
363
public void setName(String name) {
364
this.name = name;
365
}
366
367
@Override
368
public String getName() {
369
return name;
370
}
371
372
private void setupResources() {
373
// Setup component resources
374
}
375
376
private void releaseResources() {
377
// Release component resources
378
}
379
380
private void validateConfiguration() throws ShiroException {
381
// Validate component configuration
382
if (name == null) {
383
throw new ShiroException("Component name must be specified");
384
}
385
}
386
}
387
388
// Using lifecycle utilities
389
List<Object> components = Arrays.asList(
390
new MySecurityComponent(),
391
new AnotherComponent(),
392
new YetAnotherComponent()
393
);
394
395
// Initialize all components
396
LifecycleUtils.init(components);
397
398
// Later, destroy all components
399
LifecycleUtils.destroy(components);
400
```
401
402
### Generic Factory Interface
403
404
Generic factory pattern support for component creation.
405
406
```java { .api }
407
/**
408
* Generic factory interface for creating instances of type T.
409
* @param <T> the type of object created by this factory
410
*/
411
public interface Factory<T> {
412
/**
413
* Creates and returns a new instance of type T.
414
* @return a new instance of type T
415
*/
416
T getInstance();
417
}
418
```
419
420
**Usage Examples:**
421
422
```java
423
// Custom realm factory
424
public class DatabaseRealmFactory implements Factory<Realm> {
425
private DataSource dataSource;
426
427
public DatabaseRealmFactory(DataSource dataSource) {
428
this.dataSource = dataSource;
429
}
430
431
@Override
432
public Realm getInstance() {
433
JdbcRealm realm = new JdbcRealm();
434
realm.setDataSource(dataSource);
435
realm.setAuthenticationQuery("SELECT password FROM users WHERE username = ?");
436
realm.setUserRolesQuery("SELECT role FROM user_roles WHERE username = ?");
437
return realm;
438
}
439
}
440
441
// Security manager factory
442
public class SecurityManagerFactory implements Factory<SecurityManager> {
443
private final Collection<Realm> realms;
444
private final CacheManager cacheManager;
445
446
public SecurityManagerFactory(Collection<Realm> realms, CacheManager cacheManager) {
447
this.realms = realms;
448
this.cacheManager = cacheManager;
449
}
450
451
@Override
452
public SecurityManager getInstance() {
453
DefaultSecurityManager sm = new DefaultSecurityManager();
454
sm.setRealms(realms);
455
sm.setCacheManager(cacheManager);
456
return sm;
457
}
458
}
459
460
// Usage
461
Factory<Realm> realmFactory = new DatabaseRealmFactory(dataSource);
462
Realm realm = realmFactory.getInstance();
463
464
Factory<SecurityManager> smFactory = new SecurityManagerFactory(
465
Collections.singletonList(realm),
466
cacheManager
467
);
468
SecurityManager securityManager = smFactory.getInstance();
469
```
470
471
### String and Collection Utilities
472
473
Utility classes for common operations on strings and collections.
474
475
```java { .api }
476
/**
477
* String manipulation utilities commonly used throughout Shiro.
478
*/
479
public final class StringUtils {
480
/**
481
* Returns true if the specified string is null or empty.
482
* @param str the string to check
483
* @return true if the string is null or empty, false otherwise
484
*/
485
public static boolean isEmpty(String str);
486
487
/**
488
* Returns true if the specified string has text (not null and not empty after trimming).
489
* @param str the string to check
490
* @return true if the string has text, false otherwise
491
*/
492
public static boolean hasText(String str);
493
494
/**
495
* Returns true if the specified string has length (not null and length > 0).
496
* @param str the string to check
497
* @return true if the string has length, false otherwise
498
*/
499
public static boolean hasLength(String str);
500
501
/**
502
* Cleans the specified string by removing leading and trailing whitespace.
503
* @param str the string to clean
504
* @return the cleaned string, or null if the input was null
505
*/
506
public static String clean(String str);
507
508
/**
509
* Splits the specified string using the specified delimiter.
510
* @param line the string to split
511
* @param delimiter the delimiter to use for splitting
512
* @return an array of tokens, or null if the input was null or empty
513
*/
514
public static String[] split(String line, String delimiter);
515
516
/**
517
* Tokenizes the specified string using the specified delimiters.
518
* @param str the string to tokenize
519
* @param delimiters the delimiters to use
520
* @return a list of tokens
521
*/
522
public static List<String> tokenizeToStringList(String str, String delimiters);
523
}
524
525
/**
526
* Collection manipulation utilities commonly used throughout Shiro.
527
*/
528
public final class CollectionUtils {
529
/**
530
* Returns true if the specified collection is null or empty.
531
* @param c the collection to check
532
* @return true if the collection is null or empty, false otherwise
533
*/
534
public static boolean isEmpty(Collection c);
535
536
/**
537
* Returns the size of the specified collection, or 0 if null.
538
* @param c the collection
539
* @return the size of the collection, or 0 if null
540
*/
541
public static int size(Collection c);
542
543
/**
544
* Returns true if the specified map is null or empty.
545
* @param m the map to check
546
* @return true if the map is null or empty, false otherwise
547
*/
548
public static boolean isEmpty(Map m);
549
550
/**
551
* Returns the size of the specified map, or 0 if null.
552
* @param m the map
553
* @return the size of the map, or 0 if null
554
*/
555
public static int size(Map m);
556
557
/**
558
* Converts the specified collection to a set.
559
* @param c the collection to convert
560
* @return a set containing the collection's elements
561
*/
562
public static Set asSet(Collection c);
563
}
564
```
565
566
**Usage Examples:**
567
568
```java
569
// String utilities
570
String username = " john.doe ";
571
if (StringUtils.hasText(username)) {
572
username = StringUtils.clean(username); // "john.doe"
573
}
574
575
String roles = "admin,user,guest";
576
String[] roleArray = StringUtils.split(roles, ","); // ["admin", "user", "guest"]
577
578
List<String> roleList = StringUtils.tokenizeToStringList(roles, ",");
579
580
// Collection utilities
581
Collection<String> permissions = getPermissions();
582
if (!CollectionUtils.isEmpty(permissions)) {
583
System.out.println("User has " + CollectionUtils.size(permissions) + " permissions");
584
}
585
586
Set<String> uniqueRoles = CollectionUtils.asSet(roleList);
587
```
588
589
### Class Loading Utilities
590
591
Utilities for class loading and reflection operations.
592
593
```java { .api }
594
/**
595
* Class loading and reflection utilities.
596
*/
597
public final class ClassUtils {
598
/**
599
* Returns the thread context class loader, or the system class loader if the context loader is null.
600
* @return the thread context class loader, or the system class loader if the context loader is null
601
*/
602
public static ClassLoader getDefaultClassLoader();
603
604
/**
605
* Loads the class with the specified name using the default class loader.
606
* @param className the name of the class to load
607
* @return the loaded class
608
* @throws ClassNotFoundException if the class cannot be found
609
*/
610
public static Class forName(String className) throws ClassNotFoundException;
611
612
/**
613
* Loads the class with the specified name using the specified class loader.
614
* @param className the name of the class to load
615
* @param classLoader the class loader to use
616
* @return the loaded class
617
* @throws ClassNotFoundException if the class cannot be found
618
*/
619
public static Class forName(String className, ClassLoader classLoader) throws ClassNotFoundException;
620
621
/**
622
* Instantiates the class with the specified name using its default constructor.
623
* @param className the name of the class to instantiate
624
* @return a new instance of the specified class
625
* @throws InstantiationException if the class cannot be instantiated
626
* @throws IllegalAccessException if the constructor is not accessible
627
* @throws ClassNotFoundException if the class cannot be found
628
*/
629
public static Object newInstance(String className) throws InstantiationException, IllegalAccessException, ClassNotFoundException;
630
631
/**
632
* Instantiates the specified class using its default constructor.
633
* @param clazz the class to instantiate
634
* @return a new instance of the specified class
635
* @throws InstantiationException if the class cannot be instantiated
636
* @throws IllegalAccessException if the constructor is not accessible
637
*/
638
public static Object newInstance(Class clazz) throws InstantiationException, IllegalAccessException;
639
640
/**
641
* Returns true if the specified class is available in the classpath.
642
* @param className the name of the class to check
643
* @return true if the class is available, false otherwise
644
*/
645
public static boolean isAvailable(String className);
646
}
647
```
648
649
**Usage Examples:**
650
651
```java
652
// Dynamic class loading
653
if (ClassUtils.isAvailable("com.company.CustomRealm")) {
654
try {
655
Class<?> realmClass = ClassUtils.forName("com.company.CustomRealm");
656
Realm customRealm = (Realm) ClassUtils.newInstance(realmClass);
657
658
// Use the dynamically loaded realm
659
securityManager.setRealm(customRealm);
660
661
} catch (Exception e) {
662
System.err.println("Failed to load custom realm: " + e.getMessage());
663
}
664
}
665
666
// Get default class loader
667
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
668
669
// Load class with specific class loader
670
Class<?> myClass = ClassUtils.forName("com.example.MyClass", classLoader);
671
Object instance = ClassUtils.newInstance(myClass);
672
```
673
674
### Concurrent Execution Support
675
676
Utilities for executing tasks with Shiro security context in multi-threaded environments.
677
678
```java { .api }
679
/**
680
* Executor that automatically associates Subject instances with executing threads.
681
*/
682
public class SubjectAwareExecutor implements Executor {
683
/**
684
* Constructor accepting the target Executor that will actually execute the commands.
685
* @param targetExecutor the target Executor that will actually execute the commands
686
*/
687
public SubjectAwareExecutor(Executor targetExecutor);
688
689
/**
690
* Executes the specified command with the current Subject automatically associated with the executing thread.
691
* @param command the command to execute
692
*/
693
public void execute(Runnable command);
694
}
695
696
/**
697
* ExecutorService that automatically associates Subject instances with executing threads.
698
*/
699
public class SubjectAwareExecutorService extends AbstractExecutorService {
700
/**
701
* Constructor accepting the target ExecutorService that will actually execute the commands.
702
* @param targetExecutorService the target ExecutorService that will actually execute the commands
703
*/
704
public SubjectAwareExecutorService(ExecutorService targetExecutorService);
705
706
/**
707
* Returns the target ExecutorService that actually executes the commands.
708
* @return the target ExecutorService that actually executes the commands
709
*/
710
public ExecutorService getTargetExecutorService();
711
712
public void execute(Runnable command);
713
public <T> Future<T> submit(Callable<T> task);
714
public <T> Future<T> submit(Runnable task, T result);
715
public Future<?> submit(Runnable task);
716
}
717
```
718
719
**Usage Examples:**
720
721
```java
722
// Subject-aware executor
723
Subject currentUser = SecurityUtils.getSubject();
724
Executor standardExecutor = Executors.newFixedThreadPool(10);
725
SubjectAwareExecutor subjectAwareExecutor = new SubjectAwareExecutor(standardExecutor);
726
727
// Execute task with subject context
728
subjectAwareExecutor.execute(() -> {
729
// This code runs with the current user's security context
730
Subject subject = SecurityUtils.getSubject();
731
if (subject.hasRole("admin")) {
732
performAdminTask();
733
}
734
});
735
736
// Subject-aware executor service
737
ExecutorService standardService = Executors.newCachedThreadPool();
738
SubjectAwareExecutorService subjectAwareService = new SubjectAwareExecutorService(standardService);
739
740
// Submit callable with subject context
741
Future<String> result = subjectAwareService.submit(() -> {
742
Subject subject = SecurityUtils.getSubject();
743
return "Task completed by user: " + subject.getPrincipal();
744
});
745
746
try {
747
String message = result.get();
748
System.out.println(message);
749
} catch (Exception e) {
750
e.printStackTrace();
751
}
752
```
753
754
## Integration Support
755
756
### Cache Manager Awareness
757
758
Interface for components that need to be aware of the cache manager.
759
760
```java { .api }
761
/**
762
* Interface implemented by components that can be configured with a CacheManager.
763
*/
764
public interface CacheManagerAware {
765
/**
766
* Sets the CacheManager that should be used for caching.
767
* @param cacheManager the CacheManager to use for caching
768
*/
769
void setCacheManager(CacheManager cacheManager);
770
}
771
```
772
773
These utilities form the foundation for building robust, secure applications with Apache Shiro, providing essential functionality for security context management, component lifecycle, and multi-threaded execution with proper security context propagation.