MentaContainer

Rev

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