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.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
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 = new Provider<Object>()
41 {
42 public Object get()
43 {
44 throw new IllegalStateException();
45 }
46 };
47
48
49
50
51 protected static final class ScopeState
52 {
53 private final ConcurrentMap<Key<?>, CachingProvider<?>> provided = new ConcurrentHashMap<>();
54
55 public <T> void seed( Class<T> clazz, Provider<T> value )
56 {
57 provided.put( Key.get( clazz ), new CachingProvider<>( value ) );
58 }
59
60 @SuppressWarnings( "unchecked" )
61 public <T> Provider<T> scope( Key<T> key, final Provider<T> unscoped )
62 {
63 Provider<?> provider = provided.get( key );
64 if ( provider == null )
65 {
66 CachingProvider<?> newValue = new CachingProvider<>( unscoped );
67 provider = provided.putIfAbsent( key, newValue );
68 if ( provider == null )
69 {
70 provider = newValue;
71 }
72 }
73 return ( Provider<T> ) provider;
74 }
75
76 public Collection<CachingProvider<?>> providers()
77 {
78 return provided.values();
79 }
80
81 }
82
83 private final List<ScopeState> values = new CopyOnWriteArrayList<>();
84
85 public void enter()
86 {
87 values.add( 0, new ScopeState() );
88 }
89
90 protected ScopeState getScopeState()
91 {
92 if ( values.isEmpty() )
93 {
94 throw new OutOfScopeException( "Cannot access session scope outside of a scoping block" );
95 }
96 return values.get( 0 );
97 }
98
99 public void exit()
100 {
101 if ( values.isEmpty() )
102 {
103 throw new IllegalStateException();
104 }
105 values.remove( 0 );
106 }
107
108 public <T> void seed( Class<T> clazz, Provider<T> value )
109 {
110 getScopeState().seed( clazz, value );
111 }
112
113 public <T> void seed( Class<T> clazz, final T value )
114 {
115 seed( clazz, new Provider<T>()
116 {
117 @Override
118 public T get()
119 {
120 return value;
121 }
122 } );
123 }
124
125 public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
126 {
127
128 return new Provider<T>()
129 {
130 @Override
131 public T get()
132 {
133 return getScopeState().scope( key, unscoped ).get();
134 }
135 };
136 }
137
138
139
140
141
142 protected static class CachingProvider<T> implements Provider<T>
143 {
144 private final Provider<T> provider;
145 private volatile T value;
146
147 CachingProvider( Provider<T> provider )
148 {
149 this.provider = provider;
150 }
151
152 public T value()
153 {
154 return value;
155 }
156
157 @Override
158 public T get()
159 {
160 if ( value == null )
161 {
162 synchronized ( this )
163 {
164 if ( value == null )
165 {
166 value = provider.get();
167 }
168 }
169 }
170 return value;
171 }
172 }
173
174 @SuppressWarnings( { "unchecked" } )
175 public static <T> Provider<T> seededKeyProvider()
176 {
177 return (Provider<T>) SEEDED_KEY_PROVIDER;
178 }
179 }