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