MentaContainer

Rev

Rev 60 | Rev 66 | 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
 
64 soliveira 9
import org.mentacontainer.Clearable;
20 soliveira 10
import org.mentacontainer.Component;
45 soliveira 11
import org.mentacontainer.ConfigurableComponent;
2 soliveira 12
import org.mentacontainer.Container;
20 soliveira 13
import org.mentacontainer.Dependency;
57 soliveira 14
import org.mentacontainer.Scope;
4 soliveira 15
import org.mentacontainer.util.InjectionUtils;
22 soliveira 16
import org.mentacontainer.util.InjectionUtils.Provider;
2 soliveira 17
 
20 soliveira 18
/**
19
 * The implementation of the IoC container.
20
 *
21
 * @author sergio.oliveira.jr@gmail.com
22
 */
2 soliveira 23
public class MentaContainer implements Container {
24
 
20 soliveira 25
        private Map<String, Component> beans = new HashMap<String, Component>();
51 soliveira 26
 
57 soliveira 27
        private Map<String, Scope> scopes = new HashMap<String, Scope>();
51 soliveira 28
 
29
        private Map<String, Object> singletonsCache = new HashMap<String, Object>();
57 soliveira 30
 
31
        private Map<String, ThreadLocal<Object>> threadLocalsCache = new HashMap<String, ThreadLocal<Object>>();
2 soliveira 32
 
20 soliveira 33
        private Set<Dependency> dependencies = new HashSet<Dependency>();
57 soliveira 34
 
60 soliveira 35
        public synchronized void clear(Scope scope) {
57 soliveira 36
 
37
                if (scope == Scope.SINGLETON) {
38
 
64 soliveira 39
                        for(String key : singletonsCache.keySet()) {
40
 
41
                                Component comp = beans.get(key);
42
 
43
                                if (comp instanceof Clearable) {
44
 
45
                                        Clearable<Object> c = (Clearable<Object>) comp;
46
 
47
                                        Object value = singletonsCache.get(key);
48
 
49
                                        c.onCleared(value);
50
                                }
51
                        }
52
 
57 soliveira 53
                        singletonsCache.clear();
54
 
55
                } else if (scope == Scope.THREAD) {
56
 
64 soliveira 57
                        for(String key : threadLocalsCache.keySet()) {
58
 
59
                                Component comp = beans.get(key);
60
 
61
                                if (comp instanceof Clearable) {
62
 
63
                                        Clearable<Object> c = (Clearable<Object>) comp;
64
 
65
                                        ThreadLocal<Object> t = threadLocalsCache.get(key);
66
 
67
                                        Object value = t.get();
68
 
69
                                        if (value != null) c.onCleared(value);
70
                                }
71
                        }
72
 
57 soliveira 73
                        for(ThreadLocal<Object> t : threadLocalsCache.values()) {
74
 
75
                                t.set(null);
76
                        }
77
                }
78
        }
58 soliveira 79
 
60 soliveira 80
        public synchronized <T> T clear(String key) {
58 soliveira 81
 
59 soliveira 82
                if (!beans.containsKey(key)) return null;
83
 
58 soliveira 84
                Scope scope = scopes.get(key);
85
 
86
                if (scope == Scope.SINGLETON) {
87
 
64 soliveira 88
                        Object value = singletonsCache.remove(key);
58 soliveira 89
 
64 soliveira 90
                        if (value != null) {
91
 
92
                                Component comp = beans.get(key);
93
 
94
                                if (comp instanceof Clearable) {
95
 
96
                                        Clearable<Object> c = (Clearable<Object>) comp;
97
 
98
                                        c.onCleared(value);
99
                                }
100
                        }
101
 
102
                        return (T) value;
103
 
58 soliveira 104
                } else if (scope == Scope.THREAD) {
105
 
106
                        ThreadLocal<Object> t = threadLocalsCache.get(key);
107
 
108
                        if (t != null) {
109
 
110
                                Object o = t.get();
111
 
112
                                if (o != null) {
113
 
64 soliveira 114
                                        Component comp = beans.get(key);
115
 
116
                                        if (comp instanceof Clearable) {
117
 
118
                                                Clearable<Object> c = (Clearable<Object>) comp;
119
 
120
                                                c.onCleared(o);
121
                                        }
122
 
58 soliveira 123
                                        t.set(null);
124
 
125
                                        return (T) o;
126
                                }
127
                        }
128
 
129
                        return null;
130
 
131
                } else if (scope == Scope.NONE) {
132
 
133
                        return null; // always...
134
 
135
                } else {
136
 
137
                        throw new UnsupportedOperationException("Scope not supported: " + scope);
138
                }
139
        }
4 soliveira 140
 
60 soliveira 141
        public synchronized <T> T get(String key) {
4 soliveira 142
 
43 soliveira 143
                if (!beans.containsKey(key)) return null;
4 soliveira 144
 
20 soliveira 145
                Component c = beans.get(key);
51 soliveira 146
 
57 soliveira 147
                Scope scope = scopes.get(key);
148
 
20 soliveira 149
                Object target = null;
4 soliveira 150
 
20 soliveira 151
                try {
4 soliveira 152
 
57 soliveira 153
                        if (scope == Scope.SINGLETON) {
4 soliveira 154
 
51 soliveira 155
                                if (singletonsCache.containsKey(key)) {
4 soliveira 156
 
51 soliveira 157
                                        target = singletonsCache.get(key);
4 soliveira 158
 
57 soliveira 159
                                        return (T) target; // no need to wire again...
4 soliveira 160
 
20 soliveira 161
                                } else {
4 soliveira 162
 
20 soliveira 163
                                        target = c.getInstance();
4 soliveira 164
 
51 soliveira 165
                                        singletonsCache.put(key, target);
20 soliveira 166
                                }
57 soliveira 167
 
168
                        } else if (scope == Scope.THREAD) {
169
 
170
                                if (threadLocalsCache.containsKey(key)) {
171
 
172
                                        ThreadLocal<Object> t = threadLocalsCache.get(key);
173
 
174
                                        target = t.get();
175
 
176
                                        if (target == null) { // different thread...
177
 
178
                                                target = c.getInstance();
179
 
180
                                                t.set(target);
181
 
182
                                                // don't return... let it be wired...
183
 
184
                                        } else {
185
 
186
                                                return (T) target; // no need to wire again...
187
 
188
                                        }
189
 
190
                                } else {
191
 
192
                                        ThreadLocal<Object> t = new ThreadLocal<Object>();
193
 
194
                                        target = c.getInstance();
195
 
196
                                        t.set(target);
197
 
198
                                        threadLocalsCache.put(key, t);
199
 
200
                                        // let it be wired...
201
                                }
202
 
203
                        } else if (scope == Scope.NONE) {
4 soliveira 204
 
20 soliveira 205
                                target = c.getInstance();
4 soliveira 206
 
57 soliveira 207
 
208
                        } else {
209
 
210
                                throw new UnsupportedOperationException("Don't know how to handle scope: " + scope);
20 soliveira 211
                        }
4 soliveira 212
 
20 soliveira 213
                        if (target != null) {
4 soliveira 214
 
20 soliveira 215
                                for (Dependency d : dependencies) {
4 soliveira 216
 
20 soliveira 217
                                        // has dependency ?
218
                                        Method m = d.check(target.getClass());
4 soliveira 219
 
20 soliveira 220
                                        if (m != null) {
4 soliveira 221
 
20 soliveira 222
                                                String sourceKey = d.getSource();
4 soliveira 223
 
20 soliveira 224
                                                if (sourceKey.equals(key)) {
4 soliveira 225
 
20 soliveira 226
                                                        // cannot depend on itself... also avoid recursive StackOverflow...
4 soliveira 227
 
20 soliveira 228
                                                        continue;
4 soliveira 229
 
20 soliveira 230
                                                }
2 soliveira 231
 
20 soliveira 232
                                                Object source = get(sourceKey);
2 soliveira 233
 
20 soliveira 234
                                                boolean isAssignable = source != null && d.getType().isAssignableFrom(source.getClass());
4 soliveira 235
 
20 soliveira 236
                                                // check if we can find the dependency and if it is
237
                                                // assignable to the target dependency
238
                                                if (isAssignable) {
4 soliveira 239
 
20 soliveira 240
                                                        try {
4 soliveira 241
 
20 soliveira 242
                                                                // inject
243
                                                                m.invoke(target, source);
4 soliveira 244
 
20 soliveira 245
                                                        } catch (Exception e) {
4 soliveira 246
 
20 soliveira 247
                                                                throw new RuntimeException("Cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = "
248
                                                                        + (source != null ? source : "NULL") + " / target = " + target, e);
4 soliveira 249
 
20 soliveira 250
                                                        }
4 soliveira 251
 
20 soliveira 252
                                                }
253
                                        }
254
                                }
4 soliveira 255
                        }
2 soliveira 256
 
41 soliveira 257
                        return (T) target; // return target nicely with all the dependencies
4 soliveira 258
 
20 soliveira 259
                } catch (Exception e) {
4 soliveira 260
 
20 soliveira 261
                        throw new RuntimeException(e);
262
                }
2 soliveira 263
        }
4 soliveira 264
 
57 soliveira 265
        public Component ioc(String key, Component component, Scope scope) {
20 soliveira 266
 
267
                beans.put(key, component);
44 soliveira 268
 
51 soliveira 269
                singletonsCache.remove(key); // just in case we are overriding a previous singleton bean...
270
 
57 soliveira 271
                threadLocalsCache.remove(key); // just in case we are overriding a previous thread local...
51 soliveira 272
 
57 soliveira 273
                scopes.put(key, scope);
274
 
20 soliveira 275
                return component;
276
        }
277
 
51 soliveira 278
        public Component ioc(String key, Component component) {
279
 
57 soliveira 280
                return ioc(key, component, Scope.NONE);
51 soliveira 281
        }
282
 
45 soliveira 283
        public ConfigurableComponent ioc(String key, Class<? extends Object> klass) {
20 soliveira 284
 
45 soliveira 285
                ConfigurableComponent cc = new MentaComponent(klass);
286
 
287
                ioc(key, cc);
288
 
289
                return cc;
20 soliveira 290
        }
291
 
57 soliveira 292
        public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope) {
20 soliveira 293
 
51 soliveira 294
                ConfigurableComponent cc = new MentaComponent(klass);
45 soliveira 295
 
57 soliveira 296
                ioc(key, cc, scope);
45 soliveira 297
 
298
                return cc;
20 soliveira 299
        }
4 soliveira 300
 
20 soliveira 301
        public Dependency autowire(Dependency d) {
4 soliveira 302
 
20 soliveira 303
                dependencies.add(d);
4 soliveira 304
 
20 soliveira 305
                return d;
306
        }
4 soliveira 307
 
20 soliveira 308
        public Dependency autowire(String property, Class<? extends Object> klass) {
309
 
310
                return autowire(property, klass, property);
311
        }
2 soliveira 312
 
20 soliveira 313
        public Dependency autowire(String property, Class<? extends Object> klass, String source) {
314
 
315
                return autowire(new MentaDependency(property, klass, source));
316
        }
2 soliveira 317
 
40 soliveira 318
        public Container populate(Object bean) {
22 soliveira 319
 
320
                Provider p = new Provider() {
321
 
322
                        public Object get(String key) {
323
 
324
                                return MentaContainer.this.get(key);
325
                        }
326
 
58 soliveira 327
                        public boolean hasValue(String key) {
22 soliveira 328
 
58 soliveira 329
                                return MentaContainer.this.check(key);
22 soliveira 330
                        }
331
 
332
                };
40 soliveira 333
 
334
                try {
2 soliveira 335
 
40 soliveira 336
                        InjectionUtils.getObject(bean, p, false, null, true, false, true);
337
 
338
                } catch(Exception e) {
339
 
340
                        throw new RuntimeException("Error populating bean: " + bean, e);
341
                }
2 soliveira 342
 
20 soliveira 343
                return this;
344
        }
2 soliveira 345
 
60 soliveira 346
        public synchronized boolean check(String key) {
58 soliveira 347
 
59 soliveira 348
                if (!beans.containsKey(key)) return false;
349
 
58 soliveira 350
                Scope scope = scopes.get(key);
351
 
352
                if (scope == Scope.NONE) {
353
 
354
                        return false; // always...
355
 
356
                } else if (scope == Scope.SINGLETON) {
357
 
358
                        return singletonsCache.containsKey(key);
359
 
360
                } else if (scope == Scope.THREAD) {
361
 
362
                        ThreadLocal<Object> t = threadLocalsCache.get(key);
363
 
364
                        return t.get() != null;
365
 
366
                } else {
367
 
368
                        throw new UnsupportedOperationException("This scope is not supported: " + scope);
369
                }
20 soliveira 370
        }
2 soliveira 371
}