1 | |
package org.apache.onami.scopes; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import com.google.inject.Key; |
23 | |
import com.google.inject.Provider; |
24 | |
import com.google.inject.ProvisionException; |
25 | |
import com.google.inject.Scope; |
26 | |
import com.google.inject.internal.CircularDependencyProxy; |
27 | |
|
28 | |
import java.util.HashMap; |
29 | |
import java.util.Map; |
30 | |
|
31 | 45 | class ConcurrentLazySingletonScopeImpl |
32 | |
implements Scope |
33 | |
{ |
34 | 3 | private static final Object NULL = new Object(); |
35 | |
|
36 | 3 | private final Map<Key<?>, LockRecord> locks = new HashMap<Key<?>, LockRecord>(); |
37 | |
|
38 | |
public <T> Provider<T> scope( final Key<T> key, final Provider<T> creator ) |
39 | |
{ |
40 | 12 | return new Provider<T>() |
41 | 12 | { |
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
private volatile Object instance; |
47 | |
|
48 | |
|
49 | |
@SuppressWarnings( "DoubleCheckedLocking" ) |
50 | |
public T get() |
51 | |
{ |
52 | 18 | if ( instance == null ) |
53 | |
{ |
54 | 12 | final LockRecord lock = getLock( key ); |
55 | |
try |
56 | |
{ |
57 | |
|
58 | 12 | synchronized ( lock ) |
59 | |
{ |
60 | 12 | if ( instance == null ) |
61 | |
{ |
62 | 12 | T provided = creator.get(); |
63 | |
|
64 | |
|
65 | 12 | if ( provided instanceof CircularDependencyProxy ) |
66 | |
{ |
67 | 0 | return provided; |
68 | |
} |
69 | |
|
70 | 12 | Object providedOrSentinel = ( provided == null ) ? NULL : provided; |
71 | 12 | if ( ( instance != null ) && ( instance != providedOrSentinel ) ) |
72 | |
{ |
73 | 0 | throw new ProvisionException( "Provider was reentrant while creating a singleton" ); |
74 | |
} |
75 | |
|
76 | 12 | instance = providedOrSentinel; |
77 | |
} |
78 | 12 | } |
79 | |
} |
80 | |
finally |
81 | |
{ |
82 | 12 | releaseLock( lock, key ); |
83 | 12 | } |
84 | |
} |
85 | |
|
86 | 18 | Object localInstance = instance; |
87 | |
|
88 | 18 | @SuppressWarnings( { "unchecked", "UnnecessaryLocalVariable" } ) T returnedInstance = |
89 | |
( localInstance != NULL ) ? (T) localInstance : null; |
90 | 18 | return returnedInstance; |
91 | |
} |
92 | |
|
93 | |
public String toString() |
94 | |
{ |
95 | 0 | return String.format( "%s[%s]", creator, instance ); |
96 | |
} |
97 | |
}; |
98 | |
} |
99 | |
|
100 | |
private LockRecord getLock( Key<?> key ) |
101 | |
{ |
102 | 12 | synchronized ( locks ) |
103 | |
{ |
104 | 12 | LockRecord lock = locks.get( key ); |
105 | 12 | if ( lock == null ) |
106 | |
{ |
107 | 12 | lock = new LockRecord(); |
108 | 12 | locks.put( key, lock ); |
109 | |
} |
110 | 12 | ++lock.useCount; |
111 | 12 | return lock; |
112 | 0 | } |
113 | |
} |
114 | |
|
115 | |
private void releaseLock( LockRecord lock, Key<?> key ) |
116 | |
{ |
117 | 12 | synchronized ( locks ) |
118 | |
{ |
119 | 12 | if ( --lock.useCount <= 0 ) |
120 | |
{ |
121 | 12 | locks.remove( key ); |
122 | |
} |
123 | 12 | } |
124 | 12 | } |
125 | |
|
126 | |
@Override |
127 | |
public String toString() |
128 | |
{ |
129 | 0 | return "ConcurrentLazySingletonScope.SCOPE"; |
130 | |
} |
131 | |
|
132 | 48 | private static class LockRecord |
133 | |
{ |
134 | 12 | private int useCount = 0; |
135 | |
} |
136 | |
} |