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 | } |