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 class ConcurrentLazySingletonScopeImpl
32 implements Scope
33 {
34 private static final Object NULL = new Object();
35
36 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 return new Provider<T>()
41 {
42
43
44
45
46 private volatile Object instance;
47
48
49 @SuppressWarnings( "DoubleCheckedLocking" )
50 public T get()
51 {
52 if ( instance == null )
53 {
54 final LockRecord lock = getLock( key );
55 try
56 {
57
58 synchronized ( lock )
59 {
60 if ( instance == null )
61 {
62 T provided = creator.get();
63
64
65 if ( provided instanceof CircularDependencyProxy )
66 {
67 return provided;
68 }
69
70 Object providedOrSentinel = ( provided == null ) ? NULL : provided;
71 if ( ( instance != null ) && ( instance != providedOrSentinel ) )
72 {
73 throw new ProvisionException( "Provider was reentrant while creating a singleton" );
74 }
75
76 instance = providedOrSentinel;
77 }
78 }
79 }
80 finally
81 {
82 releaseLock( lock, key );
83 }
84 }
85
86 Object localInstance = instance;
87
88 @SuppressWarnings( { "unchecked", "UnnecessaryLocalVariable" } ) T returnedInstance =
89 ( localInstance != NULL ) ? (T) localInstance : null;
90 return returnedInstance;
91 }
92
93 public String toString()
94 {
95 return String.format( "%s[%s]", creator, instance );
96 }
97 };
98 }
99
100 private LockRecord getLock( Key<?> key )
101 {
102 synchronized ( locks )
103 {
104 LockRecord lock = locks.get( key );
105 if ( lock == null )
106 {
107 lock = new LockRecord();
108 locks.put( key, lock );
109 }
110 ++lock.useCount;
111 return lock;
112 }
113 }
114
115 private void releaseLock( LockRecord lock, Key<?> key )
116 {
117 synchronized ( locks )
118 {
119 if ( --lock.useCount <= 0 )
120 {
121 locks.remove( key );
122 }
123 }
124 }
125
126 @Override
127 public String toString()
128 {
129 return "ConcurrentLazySingletonScope.SCOPE";
130 }
131
132 private static class LockRecord
133 {
134 private int useCount = 0;
135 }
136 }