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.Collections;
23 import java.util.LinkedList;
24 import java.util.Map;
25
26 import com.google.common.collect.ImmutableMap;
27 import com.google.common.collect.Maps;
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 import com.google.inject.util.Providers;
33
34 public class SessionScope
35 implements Scope
36 {
37
38
39
40 public static class Memento
41 {
42 final Map<Key<?>, Provider<?>> seeded;
43
44 Memento( final Map<Key<?>, Provider<?>> seeded )
45 {
46 this.seeded = ImmutableMap.copyOf( seeded );
47 }
48 }
49
50 private static final Provider<Object> SEEDED_KEY_PROVIDER = new Provider<Object>()
51 {
52 public Object get()
53 {
54 throw new IllegalStateException();
55 }
56 };
57
58 private static final class ScopeState
59 {
60 public final Map<Key<?>, Provider<?>> seeded = Maps.newHashMap();
61
62 public final Map<Key<?>, Object> provided = Maps.newHashMap();
63 }
64
65 private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<>();
66
67 public void enter()
68 {
69 LinkedList<ScopeState> stack = values.get();
70 if ( stack == null )
71 {
72 stack = new LinkedList<>();
73 values.set( stack );
74 }
75 stack.addFirst( new ScopeState() );
76 }
77
78
79
80
81 public void enter( Memento memento )
82 {
83 enter();
84 getScopeState().seeded.putAll( memento.seeded );
85 }
86
87 private ScopeState getScopeState()
88 {
89 LinkedList<ScopeState> stack = values.get();
90 if ( stack == null || stack.isEmpty() )
91 {
92 throw new IllegalStateException();
93 }
94 return stack.getFirst();
95 }
96
97 public void exit()
98 {
99 final LinkedList<ScopeState> stack = values.get();
100 if ( stack == null || stack.isEmpty() )
101 {
102 throw new IllegalStateException();
103 }
104 stack.removeFirst();
105 if ( stack.isEmpty() )
106 {
107 values.remove();
108 }
109 }
110
111
112
113
114 public Memento memento()
115 {
116 LinkedList<ScopeState> stack = values.get();
117 return new Memento( stack != null ? stack.getFirst().seeded : Collections.<Key<?>, Provider<?>>emptyMap() );
118 }
119
120 public <T> void seed( Class<T> clazz, Provider<T> value )
121 {
122 getScopeState().seeded.put( Key.get( clazz ), value );
123 }
124
125 public <T> void seed( Class<T> clazz, final T value )
126 {
127 getScopeState().seeded.put( Key.get( clazz ), Providers.of( value ) );
128 }
129
130 public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
131 {
132 return new Provider<T>()
133 {
134 @SuppressWarnings( "unchecked" )
135 public T get()
136 {
137 LinkedList<ScopeState> stack = values.get();
138 if ( stack == null || stack.isEmpty() )
139 {
140 throw new OutOfScopeException( "Cannot access " + key + " outside of a scoping block" );
141 }
142
143 ScopeState state = stack.getFirst();
144
145 Provider<?> seeded = state.seeded.get( key );
146
147 if ( seeded != null )
148 {
149 return (T) seeded.get();
150 }
151
152 T provided = (T) state.provided.get( key );
153 if ( provided == null && unscoped != null )
154 {
155 provided = unscoped.get();
156 state.provided.put( key, provided );
157 }
158
159 return provided;
160 }
161 };
162 }
163
164 @SuppressWarnings( { "unchecked" } )
165 public static <T> Provider<T> seededKeyProvider()
166 {
167 return (Provider<T>) SEEDED_KEY_PROVIDER;
168 }
169 }