Rev 51 | Rev 58 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | soliveira | 1 | package org.mentacontainer.impl; |
2 | |||
3 | import java.lang.reflect.Method; |
||
4 | import java.util.HashMap; |
||
5 | import java.util.HashSet; |
||
6 | import java.util.Map; |
||
7 | import java.util.Set; |
||
8 | |||
20 | soliveira | 9 | import org.mentacontainer.Component; |
45 | soliveira | 10 | import org.mentacontainer.ConfigurableComponent; |
2 | soliveira | 11 | import org.mentacontainer.Container; |
20 | soliveira | 12 | import org.mentacontainer.Dependency; |
57 | soliveira | 13 | import org.mentacontainer.Scope; |
4 | soliveira | 14 | import org.mentacontainer.util.InjectionUtils; |
22 | soliveira | 15 | import org.mentacontainer.util.InjectionUtils.Provider; |
2 | soliveira | 16 | |
20 | soliveira | 17 | /** |
18 | * The implementation of the IoC container. |
||
19 | * |
||
20 | * @author sergio.oliveira.jr@gmail.com |
||
21 | */ |
||
2 | soliveira | 22 | public class MentaContainer implements Container { |
23 | |||
20 | soliveira | 24 | private Map<String, Component> beans = new HashMap<String, Component>(); |
51 | soliveira | 25 | |
57 | soliveira | 26 | private Map<String, Scope> scopes = new HashMap<String, Scope>(); |
51 | soliveira | 27 | |
28 | private Map<String, Object> singletonsCache = new HashMap<String, Object>(); |
||
57 | soliveira | 29 | |
30 | private Map<String, ThreadLocal<Object>> threadLocalsCache = new HashMap<String, ThreadLocal<Object>>(); |
||
2 | soliveira | 31 | |
20 | soliveira | 32 | private Set<Dependency> dependencies = new HashSet<Dependency>(); |
57 | soliveira | 33 | |
34 | public void clear(Scope scope) { |
||
35 | |||
36 | if (scope == Scope.SINGLETON) { |
||
37 | |||
38 | singletonsCache.clear(); |
||
39 | |||
40 | } else if (scope == Scope.THREAD) { |
||
41 | |||
42 | for(ThreadLocal<Object> t : threadLocalsCache.values()) { |
||
43 | |||
44 | t.set(null); |
||
45 | } |
||
46 | } |
||
47 | } |
||
4 | soliveira | 48 | |
41 | soliveira | 49 | public <T> T get(String key) { |
4 | soliveira | 50 | |
43 | soliveira | 51 | if (!beans.containsKey(key)) return null; |
4 | soliveira | 52 | |
20 | soliveira | 53 | Component c = beans.get(key); |
51 | soliveira | 54 | |
57 | soliveira | 55 | Scope scope = scopes.get(key); |
56 | |||
20 | soliveira | 57 | Object target = null; |
4 | soliveira | 58 | |
20 | soliveira | 59 | try { |
4 | soliveira | 60 | |
57 | soliveira | 61 | if (scope == Scope.SINGLETON) { |
4 | soliveira | 62 | |
51 | soliveira | 63 | if (singletonsCache.containsKey(key)) { |
4 | soliveira | 64 | |
51 | soliveira | 65 | target = singletonsCache.get(key); |
4 | soliveira | 66 | |
57 | soliveira | 67 | return (T) target; // no need to wire again... |
4 | soliveira | 68 | |
20 | soliveira | 69 | } else { |
4 | soliveira | 70 | |
20 | soliveira | 71 | target = c.getInstance(); |
4 | soliveira | 72 | |
51 | soliveira | 73 | singletonsCache.put(key, target); |
20 | soliveira | 74 | } |
57 | soliveira | 75 | |
76 | } else if (scope == Scope.THREAD) { |
||
77 | |||
78 | if (threadLocalsCache.containsKey(key)) { |
||
79 | |||
80 | ThreadLocal<Object> t = threadLocalsCache.get(key); |
||
81 | |||
82 | target = t.get(); |
||
83 | |||
84 | if (target == null) { // different thread... |
||
85 | |||
86 | target = c.getInstance(); |
||
87 | |||
88 | t.set(target); |
||
89 | |||
90 | // don't return... let it be wired... |
||
91 | |||
92 | } else { |
||
93 | |||
94 | return (T) target; // no need to wire again... |
||
95 | |||
96 | } |
||
97 | |||
98 | } else { |
||
99 | |||
100 | ThreadLocal<Object> t = new ThreadLocal<Object>(); |
||
101 | |||
102 | target = c.getInstance(); |
||
103 | |||
104 | t.set(target); |
||
105 | |||
106 | threadLocalsCache.put(key, t); |
||
107 | |||
108 | // let it be wired... |
||
109 | } |
||
110 | |||
111 | } else if (scope == Scope.NONE) { |
||
4 | soliveira | 112 | |
20 | soliveira | 113 | target = c.getInstance(); |
4 | soliveira | 114 | |
57 | soliveira | 115 | |
116 | } else { |
||
117 | |||
118 | throw new UnsupportedOperationException("Don't know how to handle scope: " + scope); |
||
20 | soliveira | 119 | } |
4 | soliveira | 120 | |
20 | soliveira | 121 | if (target != null) { |
4 | soliveira | 122 | |
20 | soliveira | 123 | for (Dependency d : dependencies) { |
4 | soliveira | 124 | |
20 | soliveira | 125 | // has dependency ? |
126 | Method m = d.check(target.getClass()); |
||
4 | soliveira | 127 | |
20 | soliveira | 128 | if (m != null) { |
4 | soliveira | 129 | |
20 | soliveira | 130 | String sourceKey = d.getSource(); |
4 | soliveira | 131 | |
20 | soliveira | 132 | if (sourceKey.equals(key)) { |
4 | soliveira | 133 | |
20 | soliveira | 134 | // cannot depend on itself... also avoid recursive StackOverflow... |
4 | soliveira | 135 | |
20 | soliveira | 136 | continue; |
4 | soliveira | 137 | |
20 | soliveira | 138 | } |
2 | soliveira | 139 | |
20 | soliveira | 140 | Object source = get(sourceKey); |
2 | soliveira | 141 | |
20 | soliveira | 142 | boolean isAssignable = source != null && d.getType().isAssignableFrom(source.getClass()); |
4 | soliveira | 143 | |
20 | soliveira | 144 | // check if we can find the dependency and if it is |
145 | // assignable to the target dependency |
||
146 | if (isAssignable) { |
||
4 | soliveira | 147 | |
20 | soliveira | 148 | try { |
4 | soliveira | 149 | |
20 | soliveira | 150 | // inject |
151 | m.invoke(target, source); |
||
4 | soliveira | 152 | |
20 | soliveira | 153 | } catch (Exception e) { |
4 | soliveira | 154 | |
20 | soliveira | 155 | throw new RuntimeException("Cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = " |
156 | + (source != null ? source : "NULL") + " / target = " + target, e); |
||
4 | soliveira | 157 | |
20 | soliveira | 158 | } |
4 | soliveira | 159 | |
20 | soliveira | 160 | } |
161 | } |
||
162 | } |
||
4 | soliveira | 163 | } |
2 | soliveira | 164 | |
41 | soliveira | 165 | return (T) target; // return target nicely with all the dependencies |
4 | soliveira | 166 | |
20 | soliveira | 167 | } catch (Exception e) { |
4 | soliveira | 168 | |
20 | soliveira | 169 | throw new RuntimeException(e); |
170 | } |
||
2 | soliveira | 171 | } |
4 | soliveira | 172 | |
57 | soliveira | 173 | public Component ioc(String key, Component component, Scope scope) { |
20 | soliveira | 174 | |
175 | beans.put(key, component); |
||
44 | soliveira | 176 | |
51 | soliveira | 177 | singletonsCache.remove(key); // just in case we are overriding a previous singleton bean... |
178 | |||
57 | soliveira | 179 | threadLocalsCache.remove(key); // just in case we are overriding a previous thread local... |
51 | soliveira | 180 | |
57 | soliveira | 181 | scopes.put(key, scope); |
182 | |||
20 | soliveira | 183 | return component; |
184 | } |
||
185 | |||
51 | soliveira | 186 | public Component ioc(String key, Component component) { |
187 | |||
57 | soliveira | 188 | return ioc(key, component, Scope.NONE); |
51 | soliveira | 189 | } |
190 | |||
45 | soliveira | 191 | public ConfigurableComponent ioc(String key, Class<? extends Object> klass) { |
20 | soliveira | 192 | |
45 | soliveira | 193 | ConfigurableComponent cc = new MentaComponent(klass); |
194 | |||
195 | ioc(key, cc); |
||
196 | |||
197 | return cc; |
||
20 | soliveira | 198 | } |
199 | |||
57 | soliveira | 200 | public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope) { |
20 | soliveira | 201 | |
51 | soliveira | 202 | ConfigurableComponent cc = new MentaComponent(klass); |
45 | soliveira | 203 | |
57 | soliveira | 204 | ioc(key, cc, scope); |
45 | soliveira | 205 | |
206 | return cc; |
||
20 | soliveira | 207 | } |
4 | soliveira | 208 | |
20 | soliveira | 209 | public Dependency autowire(Dependency d) { |
4 | soliveira | 210 | |
20 | soliveira | 211 | dependencies.add(d); |
4 | soliveira | 212 | |
20 | soliveira | 213 | return d; |
214 | } |
||
4 | soliveira | 215 | |
20 | soliveira | 216 | public Dependency autowire(String property, Class<? extends Object> klass) { |
217 | |||
218 | return autowire(property, klass, property); |
||
219 | } |
||
2 | soliveira | 220 | |
20 | soliveira | 221 | public Dependency autowire(String property, Class<? extends Object> klass, String source) { |
222 | |||
223 | return autowire(new MentaDependency(property, klass, source)); |
||
224 | } |
||
2 | soliveira | 225 | |
40 | soliveira | 226 | public Container populate(Object bean) { |
22 | soliveira | 227 | |
228 | Provider p = new Provider() { |
||
229 | |||
230 | public Object get(String key) { |
||
231 | |||
232 | return MentaContainer.this.get(key); |
||
233 | } |
||
234 | |||
235 | public boolean contains(String key) { |
||
236 | |||
237 | return MentaContainer.this.contains(key); |
||
238 | } |
||
239 | |||
240 | }; |
||
40 | soliveira | 241 | |
242 | try { |
||
2 | soliveira | 243 | |
40 | soliveira | 244 | InjectionUtils.getObject(bean, p, false, null, true, false, true); |
245 | |||
246 | } catch(Exception e) { |
||
247 | |||
248 | throw new RuntimeException("Error populating bean: " + bean, e); |
||
249 | } |
||
2 | soliveira | 250 | |
20 | soliveira | 251 | return this; |
252 | } |
||
2 | soliveira | 253 | |
20 | soliveira | 254 | public boolean contains(String key) { |
2 | soliveira | 255 | |
20 | soliveira | 256 | return beans.containsKey(key); |
257 | } |
||
2 | soliveira | 258 | } |