MentaContainer

Rev

Rev 51 | Rev 58 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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