MentaContainer

Rev

Rev 93 | Rev 96 | 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.Constructor;
4
import java.lang.reflect.Method;
5
import java.util.HashMap;
6
import java.util.Iterator;
7
import java.util.LinkedList;
8
import java.util.List;
9
import java.util.Map;
10
 
88 soliveira 11
import org.mentacontainer.ConfigurableFactory;
91 soliveira 12
import org.mentacontainer.Container;
2 soliveira 13
import org.mentacontainer.util.FindMethod;
14
 
20 soliveira 15
/**
93 soliveira 16
 * The implementation of the Configurable Factory.
20 soliveira 17
 *
18
 * @author sergio.oliveira.jr@gmail.com
19
 */
93 soliveira 20
class ClassFactory implements ConfigurableFactory {
20 soliveira 21
 
91 soliveira 22
                private final Container container;
23
 
20 soliveira 24
            private final Class<? extends Object> klass;
2 soliveira 25
 
26
            private Map<String, Object> props = null;
27
 
28
            private List<Object> initValues = null;
29
 
91 soliveira 30
            private List<Class<? extends Object>> initTypes = null;
31
 
2 soliveira 32
            private Constructor<? extends Object> constructor = null;
33
 
34
            private Map<String, Method> cache = null;
35
 
91 soliveira 36
            public ClassFactory(Container container, Class<? extends Object> klass) {
37
 
38
                this.container = container;
39
 
2 soliveira 40
                this.klass = klass;
41
            }
42
 
84 soliveira 43
            @Override
91 soliveira 44
            public ConfigurableFactory addPropertyValue(String name, Object value) {
86 soliveira 45
 
2 soliveira 46
                if (props == null) {
47
 
48
                    props = new HashMap<String, Object>();
49
 
50
                    cache = new HashMap<String, Method>();
51
                }
52
 
53
                props.put(name, value);
20 soliveira 54
 
55
                return this;
2 soliveira 56
            }
57
 
84 soliveira 58
            @Override
91 soliveira 59
            public ConfigurableFactory addPropertyDependency(String property, String key) {
2 soliveira 60
 
91 soliveira 61
                return addPropertyValue(property, new DependencyKey(key));
62
            }
63
 
64
            @Override
65
            public ConfigurableFactory addInitDependency(String key) {
66
 
67
                return addInitValue(new DependencyKey(key), container.getType(key));
68
            }
69
 
70
            private ConfigurableFactory addInitValue(Object value, Class<? extends Object> type) {
71
 
2 soliveira 72
                if (initValues == null) {
73
 
74
                    initValues = new LinkedList<Object>();
91 soliveira 75
 
76
                    initTypes = new LinkedList<Class<? extends Object>>();
2 soliveira 77
                }
78
 
79
                initValues.add(value);
20 soliveira 80
 
91 soliveira 81
                initTypes.add(type);
82
 
20 soliveira 83
                return this;
2 soliveira 84
            }
85
 
91 soliveira 86
            @Override
87
            public ConfigurableFactory addInitValue(Object value) {
2 soliveira 88
 
91 soliveira 89
                return addInitValue(value, value.getClass());
90
            }
91
 
92
            @Override
92 soliveira 93
            public ConfigurableFactory addInitPrimitive(Object value) {
91 soliveira 94
 
92 soliveira 95
                Class<? extends Object> primitive = getPrimitiveFrom(value);
91 soliveira 96
 
92 soliveira 97
                if (primitive == null) throw new IllegalArgumentException("Value is not a primitive: " + value);
91 soliveira 98
 
92 soliveira 99
                return addInitValue(value, primitive);
91 soliveira 100
            }
101
 
92 soliveira 102
            private List<Class<? extends Object>> convertToPrimitives(List<Class<? extends Object>> list) {
91 soliveira 103
 
92 soliveira 104
                Iterator<Class<? extends Object>> iter = list.iterator();
91 soliveira 105
 
92 soliveira 106
                List<Class<? extends Object>> results = new LinkedList<Class<? extends Object>>();
91 soliveira 107
 
92 soliveira 108
                while(iter.hasNext()) {
109
 
110
                        Class<? extends Object> klass = iter.next();
111
 
112
                        Class<? extends Object> primitive = getPrimitiveFrom(klass);
113
 
114
                        if (primitive != null) {
115
 
116
                                results.add(primitive);
117
 
118
                        } else {
119
 
120
                                results.add(klass);
121
                        }
122
                }
91 soliveira 123
 
92 soliveira 124
                return results;
91 soliveira 125
            }
126
 
127
            private Class<? extends Object>[] getClasses(List<Class<? extends Object>> values) {
128
 
2 soliveira 129
                Class<? extends Object>[] types = (Class<? extends Object>[]) new Class[values.size()];
130
 
91 soliveira 131
                return values.toArray(types);
2 soliveira 132
            }
133
 
134
            private Object [] getValues(List<Object> values) throws InstantiationException {
135
 
136
                Object [] array = new Object[values.size()];
137
 
138
                int index = 0;
139
 
140
                Iterator<Object> iter = values.iterator();
141
 
142
                while(iter.hasNext()) {
143
 
144
                        Object obj = iter.next();
91 soliveira 145
 
146
                        if (obj instanceof DependencyKey) {
147
 
148
                                DependencyKey dk = (DependencyKey) obj;
149
 
150
                                array[index++] = container.get(dk.getKey());
151
 
152
                        } else {
2 soliveira 153
 
91 soliveira 154
                                array[index++] = obj;
155
                        }
2 soliveira 156
                }
157
 
158
                return array;
159
            }
160
 
161
                /*
162
                 * Use reflection to set a property in the bean
163
                 */
40 soliveira 164
                private void setValue(Object bean, String name, Object value) {
2 soliveira 165
 
166
                        try {
20 soliveira 167
 
2 soliveira 168
                                StringBuffer sb = new StringBuffer(30);
169
                                sb.append("set");
170
                                sb.append(name.substring(0,1).toUpperCase());
20 soliveira 171
 
2 soliveira 172
                                if (name.length() > 1) sb.append(name.substring(1));
173
 
174
                    String methodName = sb.toString();
175
 
176
                    if (!cache.containsKey(name)) {
20 soliveira 177
 
2 soliveira 178
                        Method m = null;
20 soliveira 179
 
2 soliveira 180
                        try {
20 soliveira 181
 
2 soliveira 182
                            m = FindMethod.getMethod(klass, methodName, new Class[] { value.getClass() });
20 soliveira 183
 
2 soliveira 184
                        } catch(Exception e) {
20 soliveira 185
 
2 soliveira 186
                            // try primitive...
20 soliveira 187
 
2 soliveira 188
                            Class<? extends Object> primitive = getPrimitiveFrom(value);
20 soliveira 189
 
2 soliveira 190
                            if (primitive != null) {
20 soliveira 191
 
2 soliveira 192
                                try {
20 soliveira 193
 
2 soliveira 194
                                    m = klass.getMethod(methodName, new Class[] { primitive });
20 soliveira 195
 
2 soliveira 196
                                } catch(Exception ex) {
197
                                        // not found!
198
                                }
199
                            }
200
 
201
                            if (m == null) {
20 soliveira 202
 
91 soliveira 203
                                throw new InstantiationException("Cannot find method for property: " + name);
2 soliveira 204
                            }
205
                        }
206
 
207
                        if (m != null) {
20 soliveira 208
 
2 soliveira 209
                            cache.put(name, m);
20 soliveira 210
 
2 soliveira 211
                            m.setAccessible(true);
212
                        }
213
                    }    
214
 
215
                    Method m = cache.get(name);
20 soliveira 216
 
2 soliveira 217
                    if (m != null) {
20 soliveira 218
 
2 soliveira 219
                        m.invoke(bean, new Object[] { value });
220
                    }                
20 soliveira 221
 
2 soliveira 222
                        } catch(Exception e) {
20 soliveira 223
 
40 soliveira 224
                                throw new RuntimeException("Error trying to set a property with reflection: " + name, e);
2 soliveira 225
                        }
226
                }
227
 
228
            private static Class<? extends Object> getPrimitiveFrom(Object w) {
229
                if (w instanceof Boolean) { return Boolean.TYPE; }
230
                else if (w instanceof Byte) { return Byte.TYPE; }
231
                else if (w instanceof Short) { return Short.TYPE; }
232
                else if (w instanceof Character) { return Character.TYPE; }
233
                else if (w instanceof Integer) { return Integer.TYPE; }
234
                else if (w instanceof Long) { return Long.TYPE; }
235
                else if (w instanceof Float) { return Float.TYPE; }
236
                else if (w instanceof Double) { return Double.TYPE; }
237
                return null;
92 soliveira 238
            }
2 soliveira 239
 
92 soliveira 240
            private static Class<? extends Object> getPrimitiveFrom(Class<? extends Object> klass) {
241
                if (klass.equals(Boolean.class)) { return Boolean.TYPE; }
242
                else if (klass.equals(Byte.class)) { return Byte.TYPE; }
243
                else if (klass.equals(Short.class)) { return Short.TYPE; }
244
                else if (klass.equals(Character.class)) { return Character.TYPE; }
245
                else if (klass.equals(Integer.class)) { return Integer.TYPE; }
246
                else if (klass.equals(Long.class)) { return Long.TYPE; }
247
                else if (klass.equals(Float.class)) { return Float.TYPE; }
248
                else if (klass.equals(Double.class)) { return Double.TYPE; }
249
                return null;
250
            }
251
 
84 soliveira 252
            @Override
41 soliveira 253
            public <T> T getInstance()  {
20 soliveira 254
 
2 soliveira 255
                Object obj = null;
20 soliveira 256
 
2 soliveira 257
                if (initValues != null && initValues.size() > 0) {
20 soliveira 258
 
2 soliveira 259
                    if (constructor == null) {
20 soliveira 260
 
2 soliveira 261
                        try {
20 soliveira 262
 
91 soliveira 263
                            constructor = klass.getConstructor(getClasses(initTypes));
20 soliveira 264
 
2 soliveira 265
                        } catch(Exception e) {
20 soliveira 266
 
92 soliveira 267
                                // try primitives...
268
 
269
                                try {
270
 
271
                                        constructor = klass.getConstructor(getClasses(convertToPrimitives(initTypes)));
272
 
273
                                } catch(Exception ee) {
274
 
275
                                        throw new RuntimeException("Cannot find a constructor for class: " + klass);
276
                                }
2 soliveira 277
                        }
278
                    }
20 soliveira 279
 
2 soliveira 280
                    try {
20 soliveira 281
 
2 soliveira 282
                        obj = constructor.newInstance(getValues(initValues));
20 soliveira 283
 
2 soliveira 284
                    } catch(Exception e) {
20 soliveira 285
 
40 soliveira 286
                        throw new RuntimeException("Cannot create instance from constructor: " + constructor, e);
2 soliveira 287
                    }
20 soliveira 288
 
2 soliveira 289
                } else {
20 soliveira 290
 
2 soliveira 291
                    try {
20 soliveira 292
 
2 soliveira 293
                        obj = klass.newInstance();
20 soliveira 294
 
2 soliveira 295
                    } catch(Exception e) {
20 soliveira 296
 
40 soliveira 297
                        throw new RuntimeException("Cannot create instance from class: " + klass, e);
2 soliveira 298
                    }
299
                }
20 soliveira 300
 
2 soliveira 301
                if (props != null && props.size() > 0) {
20 soliveira 302
 
2 soliveira 303
                    Iterator<String> iter = props.keySet().iterator();
20 soliveira 304
 
2 soliveira 305
                    while(iter.hasNext()) {
20 soliveira 306
 
2 soliveira 307
                        String name = iter.next();
20 soliveira 308
 
2 soliveira 309
                        Object value = props.get(name);
20 soliveira 310
 
91 soliveira 311
                        if (value instanceof DependencyKey) {
312
 
313
                                DependencyKey dk = (DependencyKey) value;
314
 
315
                                value = container.get(dk.getKey());
316
                        }
317
 
2 soliveira 318
                        setValue(obj, name, value);
319
                    }
320
                }
20 soliveira 321
 
41 soliveira 322
                return (T) obj;
2 soliveira 323
            }
91 soliveira 324
 
94 soliveira 325
            /*
326
            private Constructor<? extends Object> findConstructor() {
327
 
328
                LinkedList<Class<? extends Object>> copy = new LinkedList<Class<? extends Object>>(initTypes);
329
 
330
                Constructor<? extends Object>[] constructors = klass.getConstructors();
331
 
332
                Constructor<? extends Object> found = null;
333
 
334
                for(Constructor<? extends Object> c : constructors) {
335
 
336
                        Class<? extends Object>[] params = c.getParameterTypes();
337
 
338
                        if (params == null || params.length == 0) continue; // skip default constructor for now...
339
 
340
                        for(Class<? extends Object> p : params) {
341
 
342
                                // first see if it was given...
343
 
344
                                Class<? extends Object> given = copy.isEmpty() ? null : copy.get(0);
345
 
346
                                if (p.equals(given)) {
347
 
348
                                        continue; // found param, let's check the other one...
349
 
350
                                } else {
351
 
352
                                        // check auto-wiring...
353
                                }
354
                        }
355
                }
356
            }
357
            */
358
 
91 soliveira 359
            private static class DependencyKey {
360
 
361
                private String key;
362
 
363
                public DependencyKey(String key) { this.key = key; }
364
 
365
                private String getKey() { return key; }
366
            }
367
 
368
            @Override
369
            public Class<? extends Object> getType() {
370
                return klass;
371
            }
2 soliveira 372
        }