MentaContainer

Rev

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