1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.session.scope.internal;
20
21 import com.google.inject.Key;
22 import com.google.inject.OutOfScopeException;
23 import com.google.inject.Provider;
24 import com.google.inject.Scope;
25 import java.util.Collection;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.CopyOnWriteArrayList;
30
31
32
33
34 public class SessionScope implements Scope {
35
36 private static final Provider<Object> SEEDED_KEY_PROVIDER = () -> {
37 throw new IllegalStateException();
38 };
39
40
41
42
43 protected static final class ScopeState {
44 private final Map<Key<?>, CachingProvider<?>> provided = new ConcurrentHashMap<>();
45
46 public <T> void seed(Class<T> clazz, Provider<T> value) {
47 provided.put(Key.get(clazz), new CachingProvider<>(value));
48 }
49
50 @SuppressWarnings("unchecked")
51 public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
52 Provider<?> provider = provided.computeIfAbsent(key, k -> new CachingProvider<>(unscoped));
53 return (Provider<T>) provider;
54 }
55
56 public Collection<CachingProvider<?>> providers() {
57 return provided.values();
58 }
59 }
60
61 private final List<ScopeState> values = new CopyOnWriteArrayList<>();
62
63 public void enter() {
64 values.add(0, new ScopeState());
65 }
66
67 protected ScopeState getScopeState() {
68 if (values.isEmpty()) {
69 throw new OutOfScopeException("Cannot access session scope outside of a scoping block");
70 }
71 return values.get(0);
72 }
73
74 public void exit() {
75 if (values.isEmpty()) {
76 throw new IllegalStateException();
77 }
78 values.remove(0);
79 }
80
81 public <T> void seed(Class<T> clazz, Provider<T> value) {
82 getScopeState().seed(clazz, value);
83 }
84
85 public <T> void seed(Class<T> clazz, final T value) {
86 seed(clazz, (Provider<T>) () -> value);
87 }
88
89 public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
90
91 return () -> getScopeState().scope(key, unscoped).get();
92 }
93
94
95
96
97
98 protected static class CachingProvider<T> implements Provider<T> {
99 private final Provider<T> provider;
100 private volatile T value;
101
102 CachingProvider(Provider<T> provider) {
103 this.provider = provider;
104 }
105
106 public T value() {
107 return value;
108 }
109
110 @Override
111 public T get() {
112 if (value == null) {
113 synchronized (this) {
114 if (value == null) {
115 value = provider.get();
116 }
117 }
118 }
119 return value;
120 }
121 }
122
123 @SuppressWarnings({"unchecked"})
124 public static <T> Provider<T> seededKeyProvider() {
125 return (Provider<T>) SEEDED_KEY_PROVIDER;
126 }
127 }