MentaContainer

Rev

Rev 57 | Rev 59 | 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
        }
58 soliveira 48
 
49
        public <T> T clear(String key) {
50
 
51
                Scope scope = scopes.get(key);
52
 
53
                if (scope == Scope.SINGLETON) {
54
 
55
                        return (T) singletonsCache.remove(key);
56
 
57
                } else if (scope == Scope.THREAD) {
58
 
59
                        ThreadLocal<Object> t = threadLocalsCache.get(key);
60
 
61
                        if (t != null) {
62
 
63
                                Object o = t.get();
64
 
65
                                if (o != null) {
66
 
67
                                        t.set(null);
68
 
69
                                        return (T) o;
70
                                }
71
                        }
72
 
73
                        return null;
74
 
75
                } else if (scope == Scope.NONE) {
76
 
77
                        return null; // always...
78
 
79
                } else {
80
 
81
                        throw new UnsupportedOperationException("Scope not supported: " + scope);
82
                }
83
        }
4 soliveira 84
 
41 soliveira 85
        public <T> T get(String key) {
4 soliveira 86
 
43 soliveira 87
                if (!beans.containsKey(key)) return null;
4 soliveira 88
 
20 soliveira 89
                Component c = beans.get(key);
51 soliveira 90
 
57 soliveira 91
                Scope scope = scopes.get(key);
92
 
20 soliveira 93
                Object target = null;
4 soliveira 94
 
20 soliveira 95
                try {
4 soliveira 96
 
57 soliveira 97
                        if (scope == Scope.SINGLETON) {
4 soliveira 98
 
51 soliveira 99
                                if (singletonsCache.containsKey(key)) {
4 soliveira 100
 
51 soliveira 101
                                        target = singletonsCache.get(key);
4 soliveira 102
 
57 soliveira 103
                                        return (T) target; // no need to wire again...
4 soliveira 104
 
20 soliveira 105
                                } else {
4 soliveira 106
 
20 soliveira 107
                                        target = c.getInstance();
4 soliveira 108
 
51 soliveira 109
                                        singletonsCache.put(key, target);
20 soliveira 110
                                }
57 soliveira 111
 
112
                        } else if (scope == Scope.THREAD) {
113
 
114
                                if (threadLocalsCache.containsKey(key)) {
115
 
116
                                        ThreadLocal<Object> t = threadLocalsCache.get(key);
117
 
118
                                        target = t.get();
119
 
120
                                        if (target == null) { // different thread...
121
 
122
                                                target = c.getInstance();
123
 
124
                                                t.set(target);
125
 
126
                                                // don't return... let it be wired...
127
 
128
                                        } else {
129
 
130
                                                return (T) target; // no need to wire again...
131
 
132
                                        }
133
 
134
                                } else {
135
 
136
                                        ThreadLocal<Object> t = new ThreadLocal<Object>();
137
 
138
                                        target = c.getInstance();
139
 
140
                                        t.set(target);
141
 
142
                                        threadLocalsCache.put(key, t);
143
 
144
                                        // let it be wired...
145
                                }
146
 
147
                        } else if (scope == Scope.NONE) {
4 soliveira 148
 
20 soliveira 149
                                target = c.getInstance();
4 soliveira 150
 
57 soliveira 151
 
152
                        } else {
153
 
154
                                throw new UnsupportedOperationException("Don't know how to handle scope: " + scope);
20 soliveira 155
                        }
4 soliveira 156
 
20 soliveira 157
                        if (target != null) {
4 soliveira 158
 
20 soliveira 159
                                for (Dependency d : dependencies) {
4 soliveira 160
 
20 soliveira 161
                                        // has dependency ?
162
                                        Method m = d.check(target.getClass());
4 soliveira 163
 
20 soliveira 164
                                        if (m != null) {
4 soliveira 165
 
20 soliveira 166
                                                String sourceKey = d.getSource();
4 soliveira 167
 
20 soliveira 168
                                                if (sourceKey.equals(key)) {
4 soliveira 169
 
20 soliveira 170
                                                        // cannot depend on itself... also avoid recursive StackOverflow...
4 soliveira 171
 
20 soliveira 172
                                                        continue;
4 soliveira 173
 
20 soliveira 174
                                                }
2 soliveira 175
 
20 soliveira 176
                                                Object source = get(sourceKey);
2 soliveira 177
 
20 soliveira 178
                                                boolean isAssignable = source != null && d.getType().isAssignableFrom(source.getClass());
4 soliveira 179
 
20 soliveira 180
                                                // check if we can find the dependency and if it is
181
                                                // assignable to the target dependency
182
                                                if (isAssignable) {
4 soliveira 183
 
20 soliveira 184
                                                        try {
4 soliveira 185
 
20 soliveira 186
                                                                // inject
187
                                                                m.invoke(target, source);
4 soliveira 188
 
20 soliveira 189
                                                        } catch (Exception e) {
4 soliveira 190
 
20 soliveira 191
                                                                throw new RuntimeException("Cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = "
192
                                                                        + (source != null ? source : "NULL") + " / target = " + target, e);
4 soliveira 193
 
20 soliveira 194
                                                        }
4 soliveira 195
 
20 soliveira 196
                                                }
197
                                        }
198
                                }
4 soliveira 199
                        }
2 soliveira 200
 
41 soliveira 201
                        return (T) target; // return target nicely with all the dependencies
4 soliveira 202
 
20 soliveira 203
                } catch (Exception e) {
4 soliveira 204
 
20 soliveira 205
                        throw new RuntimeException(e);
206
                }
2 soliveira 207
        }
4 soliveira 208
 
57 soliveira 209
        public Component ioc(String key, Component component, Scope scope) {
20 soliveira 210
 
211
                beans.put(key, component);
44 soliveira 212
 
51 soliveira 213
                singletonsCache.remove(key); // just in case we are overriding a previous singleton bean...
214
 
57 soliveira 215
                threadLocalsCache.remove(key); // just in case we are overriding a previous thread local...
51 soliveira 216
 
57 soliveira 217
                scopes.put(key, scope);
218
 
20 soliveira 219
                return component;
220
        }
221
 
51 soliveira 222
        public Component ioc(String key, Component component) {
223
 
57 soliveira 224
                return ioc(key, component, Scope.NONE);
51 soliveira 225
        }
226
 
45 soliveira 227
        public ConfigurableComponent ioc(String key, Class<? extends Object> klass) {
20 soliveira 228
 
45 soliveira 229
                ConfigurableComponent cc = new MentaComponent(klass);
230
 
231
                ioc(key, cc);
232
 
233
                return cc;
20 soliveira 234
        }
235
 
57 soliveira 236
        public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope) {
20 soliveira 237
 
51 soliveira 238
                ConfigurableComponent cc = new MentaComponent(klass);
45 soliveira 239
 
57 soliveira 240
                ioc(key, cc, scope);
45 soliveira 241
 
242
                return cc;
20 soliveira 243
        }
4 soliveira 244
 
20 soliveira 245
        public Dependency autowire(Dependency d) {
4 soliveira 246
 
20 soliveira 247
                dependencies.add(d);
4 soliveira 248
 
20 soliveira 249
                return d;
250
        }
4 soliveira 251
 
20 soliveira 252
        public Dependency autowire(String property, Class<? extends Object> klass) {
253
 
254
                return autowire(property, klass, property);
255
        }
2 soliveira 256
 
20 soliveira 257
        public Dependency autowire(String property, Class<? extends Object> klass, String source) {
258
 
259
                return autowire(new MentaDependency(property, klass, source));
260
        }
2 soliveira 261
 
40 soliveira 262
        public Container populate(Object bean) {
22 soliveira 263
 
264
                Provider p = new Provider() {
265
 
266
                        public Object get(String key) {
267
 
268
                                return MentaContainer.this.get(key);
269
                        }
270
 
58 soliveira 271
                        public boolean hasValue(String key) {
22 soliveira 272
 
58 soliveira 273
                                return MentaContainer.this.check(key);
22 soliveira 274
                        }
275
 
276
                };
40 soliveira 277
 
278
                try {
2 soliveira 279
 
40 soliveira 280
                        InjectionUtils.getObject(bean, p, false, null, true, false, true);
281
 
282
                } catch(Exception e) {
283
 
284
                        throw new RuntimeException("Error populating bean: " + bean, e);
285
                }
2 soliveira 286
 
20 soliveira 287
                return this;
288
        }
2 soliveira 289
 
58 soliveira 290
        public boolean check(String key) {
291
 
292
                Scope scope = scopes.get(key);
293
 
294
                if (scope == Scope.NONE) {
295
 
296
                        return false; // always...
297
 
298
                } else if (scope == Scope.SINGLETON) {
299
 
300
                        return singletonsCache.containsKey(key);
301
 
302
                } else if (scope == Scope.THREAD) {
303
 
304
                        ThreadLocal<Object> t = threadLocalsCache.get(key);
305
 
306
                        return t.get() != null;
307
 
308
                } else {
309
 
310
                        throw new UnsupportedOperationException("This scope is not supported: " + scope);
311
                }
20 soliveira 312
        }
2 soliveira 313
}