1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.grouplens.grapht;
21
22 import com.google.common.base.Function;
23 import com.google.common.base.Throwables;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.collect.ImmutableSetMultimap;
26 import com.google.common.collect.Maps;
27 import com.google.common.collect.SetMultimap;
28 import org.apache.commons.lang3.reflect.MethodUtils;
29 import org.grouplens.grapht.graph.DAGEdge;
30 import org.grouplens.grapht.graph.DAGNode;
31 import org.grouplens.grapht.reflect.Desire;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import javax.annotation.Nullable;
36 import javax.annotation.PreDestroy;
37 import java.lang.reflect.Method;
38 import java.util.*;
39
40
41
42
43
44
45
46
47
48 public class InjectionContainer {
49 private static final Logger logger = LoggerFactory.getLogger(InjectionContainer.class);
50
51 private final CachePolicy defaultCachePolicy;
52 private final Map<DAGNode<Component, Dependency>, Instantiator> providerCache;
53 private final LifecycleManager manager;
54
55
56
57
58
59 public static InjectionContainer create() {
60 return create(CachePolicy.MEMOIZE);
61 }
62
63
64
65
66
67
68 public static InjectionContainer create(CachePolicy dft) {
69 return new InjectionContainer(dft, null);
70 }
71
72
73
74
75
76
77
78 public static InjectionContainer create(CachePolicy dft, LifecycleManager mgr) {
79 return new InjectionContainer(dft, mgr);
80 }
81
82 private InjectionContainer(CachePolicy dft, LifecycleManager mgr) {
83 defaultCachePolicy = dft;
84 providerCache = new WeakHashMap<DAGNode<Component, Dependency>, Instantiator>();
85 manager = mgr;
86 }
87
88
89
90
91
92
93
94
95
96
97 public Instantiator makeInstantiator(DAGNode<Component, Dependency> node) {
98 return makeInstantiator(node, ImmutableSetMultimap.<DAGNode<Component, Dependency>, DAGEdge<Component, Dependency>>of());
99 }
100
101
102
103
104
105
106
107
108
109
110 public Instantiator makeInstantiator(DAGNode<Component, Dependency> node,
111 SetMultimap<DAGNode<Component, Dependency>, DAGEdge<Component, Dependency>> backEdges) {
112 Instantiator cached;
113 synchronized (providerCache) {
114 cached = providerCache.get(node);
115 }
116 if (cached == null) {
117 logger.debug("Node has not been memoized, instantiating: {}", node.getLabel());
118
119 Map<Desire, Instantiator> depMap = makeDependencyMap(node, backEdges);
120
121 Instantiator raw = node.getLabel().getSatisfaction().makeInstantiator(depMap, manager);
122
123 CachePolicy policy = node.getLabel().getCachePolicy();
124 if (policy.equals(CachePolicy.NO_PREFERENCE)) {
125 policy = defaultCachePolicy;
126 }
127 if (policy.equals(CachePolicy.MEMOIZE)) {
128
129 cached = Instantiators.memoize(raw);
130 } else {
131
132
133 assert policy.equals(CachePolicy.NEW_INSTANCE);
134 cached = raw;
135 }
136 synchronized (providerCache) {
137 if (!providerCache.containsKey(node)) {
138 providerCache.put(node, cached);
139 } else {
140 logger.debug("two threads built instantiator for {}, discarding 2nd build", node);
141 cached = providerCache.get(node);
142 }
143 }
144 }
145 return cached;
146 }
147
148 private Map<Desire, Instantiator> makeDependencyMap(DAGNode<Component, Dependency> node, SetMultimap<DAGNode<Component, Dependency>, DAGEdge<Component, Dependency>> backEdges) {
149 Set<DAGEdge<Component,Dependency>> edges = node.getOutgoingEdges();
150 if (backEdges.containsKey(node)) {
151 ImmutableSet.Builder<DAGEdge<Component,Dependency>> bld = ImmutableSet.builder();
152 edges = bld.addAll(edges)
153 .addAll(backEdges.get(node))
154 .build();
155 }
156
157 ImmutableSet.Builder<Desire> desires = ImmutableSet.builder();
158 for (DAGEdge<Component,Dependency> edge: edges) {
159 desires.add(edge.getLabel().getInitialDesire());
160 }
161 return Maps.asMap(desires.build(), new DepLookup(edges, backEdges));
162 }
163
164
165
166
167
168 @Nullable
169 public LifecycleManager getLifecycleManager() {
170 return manager;
171 }
172
173
174
175
176 private class DepLookup implements Function<Desire,Instantiator> {
177 private final Set<DAGEdge<Component, Dependency>> edges;
178 private final SetMultimap<DAGNode<Component, Dependency>, DAGEdge<Component, Dependency>> backEdges;
179
180
181
182
183
184
185 public DepLookup(Set<DAGEdge<Component,Dependency>> edges,
186 SetMultimap<DAGNode<Component, Dependency>, DAGEdge<Component, Dependency>> backEdges) {
187 this.edges = edges;
188 this.backEdges = backEdges;
189 }
190
191 @Nullable
192 @Override
193 public Instantiator apply(@Nullable Desire input) {
194 for (DAGEdge<Component,Dependency> edge: edges) {
195 if (edge.getLabel().getInitialDesire().equals(input)) {
196 return makeInstantiator(edge.getTail(), backEdges);
197 }
198 }
199 return null;
200 }
201 }
202 }