MentaContainer

Rev

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
}