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