1
2
3
4
5
6
7
8
9
10
11 package org.mule.config.spring.parsers.assembly;
12
13 import org.mule.config.spring.MuleHierarchicalBeanDefinitionParserDelegate;
14 import org.mule.config.spring.parsers.assembly.configuration.PropertyConfiguration;
15 import org.mule.config.spring.parsers.assembly.configuration.SingleProperty;
16 import org.mule.config.spring.parsers.assembly.configuration.SinglePropertyLiteral;
17 import org.mule.config.spring.parsers.assembly.configuration.SinglePropertyWrapper;
18 import org.mule.config.spring.parsers.collection.ChildListEntryDefinitionParser;
19 import org.mule.config.spring.parsers.collection.ChildMapEntryDefinitionParser;
20 import org.mule.config.spring.util.SpringXMLUtils;
21 import org.mule.util.ClassUtils;
22 import org.mule.util.MapCombiner;
23
24 import java.lang.reflect.Method;
25 import java.util.Collection;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.StringTokenizer;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.springframework.beans.MutablePropertyValues;
33 import org.springframework.beans.PropertyValue;
34 import org.springframework.beans.PropertyValues;
35 import org.springframework.beans.factory.config.BeanDefinition;
36 import org.springframework.beans.factory.config.MapFactoryBean;
37 import org.springframework.beans.factory.config.RuntimeBeanReference;
38 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
39 import org.springframework.beans.factory.support.ManagedList;
40 import org.springframework.beans.factory.support.ManagedMap;
41 import org.w3c.dom.Attr;
42
43 public class DefaultBeanAssembler implements BeanAssembler
44 {
45
46 private static Log logger = LogFactory.getLog(DefaultBeanAssembler.class);
47 private PropertyConfiguration beanConfig;
48 protected BeanDefinitionBuilder bean;
49 protected PropertyConfiguration targetConfig;
50 protected BeanDefinition target;
51
52 public DefaultBeanAssembler(PropertyConfiguration beanConfig, BeanDefinitionBuilder bean,
53 PropertyConfiguration targetConfig, BeanDefinition target)
54 {
55 this.beanConfig = beanConfig;
56 this.bean = bean;
57 this.targetConfig = targetConfig;
58 this.target = target;
59 }
60
61 public BeanDefinitionBuilder getBean()
62 {
63 return bean;
64 }
65
66 protected void setBean(BeanDefinitionBuilder bean)
67 {
68 this.bean = bean;
69 }
70
71 public BeanDefinition getTarget()
72 {
73 return target;
74 }
75
76 protected PropertyConfiguration getBeanConfig()
77 {
78 return beanConfig;
79 }
80
81 protected PropertyConfiguration getTargetConfig()
82 {
83 return targetConfig;
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97 public void extendBean(Attr attribute)
98 {
99 String oldName = SpringXMLUtils.attributeName(attribute);
100 if (!beanConfig.isIgnored(oldName))
101 {
102 logger.debug(attribute + " for " + bean.getBeanDefinition().getBeanClassName());
103 String oldValue = attribute.getNodeValue();
104 String newName = bestGuessName(beanConfig, oldName, bean.getBeanDefinition().getBeanClassName());
105 Object newValue = beanConfig.translateValue(oldName, oldValue);
106 addPropertyWithReference(bean.getBeanDefinition().getPropertyValues(),
107 beanConfig.getSingleProperty(oldName), newName, newValue);
108 }
109 }
110
111
112
113
114
115
116
117
118 public void extendBean(String newName, Object newValue, boolean isReference)
119 {
120 addPropertyWithReference(bean.getBeanDefinition().getPropertyValues(),
121 new SinglePropertyLiteral(isReference), newName, newValue);
122 }
123
124
125
126
127
128
129
130 public void extendTarget(Attr attribute)
131 {
132 String oldName = SpringXMLUtils.attributeName(attribute);
133 String oldValue = attribute.getNodeValue();
134 String newName = bestGuessName(targetConfig, oldName, bean.getBeanDefinition().getBeanClassName());
135 Object newValue = targetConfig.translateValue(oldName, oldValue);
136 addPropertyWithReference(target.getPropertyValues(),
137 targetConfig.getSingleProperty(oldName), newName, newValue);
138 }
139
140
141
142
143
144
145
146
147 public void extendTarget(String newName, Object newValue, boolean isReference)
148 {
149 assertTargetPresent();
150 addPropertyWithReference(target.getPropertyValues(),
151 new SinglePropertyLiteral(isReference), newName, newValue);
152 }
153
154 public void extendTarget(String oldName, String newName, Object newValue)
155 {
156 assertTargetPresent();
157 addPropertyWithReference(target.getPropertyValues(),
158 new SinglePropertyWrapper(oldName, getTargetConfig()), newName, newValue);
159 }
160
161
162
163
164
165
166
167
168 public void insertBeanInTarget(String oldName)
169 {
170 logger.debug("insert " + bean.getBeanDefinition().getBeanClassName() + " -> " + target.getBeanClassName());
171 assertTargetPresent();
172 String beanClass = bean.getBeanDefinition().getBeanClassName();
173 PropertyValues sourceProperties = bean.getRawBeanDefinition().getPropertyValues();
174 String newName = bestGuessName(targetConfig, oldName, target.getBeanClassName());
175 MutablePropertyValues targetProperties = target.getPropertyValues();
176 PropertyValue pv = targetProperties.getPropertyValue(newName);
177 Object oldValue = null == pv ? null : pv.getValue();
178
179 if (! targetConfig.isIgnored(oldName))
180 {
181 if (targetConfig.isCollection(oldName) ||
182 beanClass.equals(ChildListEntryDefinitionParser.ListEntry.class.getName()))
183 {
184 if (null == oldValue)
185 {
186 if (beanClass.equals(ChildMapEntryDefinitionParser.KeyValuePair.class.getName()) ||
187 beanClass.equals(MapEntryCombiner.class.getName()) ||
188 beanClass.equals(MapFactoryBean.class.getName()))
189 {
190
191
192 BeanDefinitionBuilder combiner = BeanDefinitionBuilder.rootBeanDefinition(MapCombiner.class);
193 targetProperties.addPropertyValue(newName, combiner.getBeanDefinition());
194 MutablePropertyValues combinerProperties = combiner.getBeanDefinition().getPropertyValues();
195 oldValue = new ManagedList();
196 pv = new PropertyValue(MapCombiner.LIST, oldValue);
197 combinerProperties.addPropertyValue(pv);
198 }
199 else
200 {
201 oldValue = new ManagedList();
202 pv = new PropertyValue(newName, oldValue);
203 targetProperties.addPropertyValue(pv);
204 }
205 }
206
207 List list = retrieveList(oldValue);
208 if (ChildMapEntryDefinitionParser.KeyValuePair.class.getName().equals(beanClass))
209 {
210 list.add(new ManagedMap());
211 retrieveMap(list.get(list.size() - 1)).put(
212 sourceProperties.getPropertyValue(ChildMapEntryDefinitionParser.KEY).getValue(),
213 sourceProperties.getPropertyValue(ChildMapEntryDefinitionParser.VALUE).getValue());
214 }
215 else if (beanClass.equals(ChildListEntryDefinitionParser.ListEntry.class.getName()))
216 {
217 list.add(sourceProperties.getPropertyValue(ChildListEntryDefinitionParser.VALUE).getValue());
218 }
219 else
220 {
221 list.add(bean.getBeanDefinition());
222 }
223 }
224 else
225 {
226
227
228 if (ChildMapEntryDefinitionParser.KeyValuePair.class.getName().equals(beanClass))
229 {
230 if (null == pv || null == oldValue)
231 {
232 pv = new PropertyValue(newName, new ManagedMap());
233 targetProperties.addPropertyValue(pv);
234 }
235 retrieveMap(pv.getValue()).put(
236 sourceProperties.getPropertyValue(ChildMapEntryDefinitionParser.KEY).getValue(),
237 sourceProperties.getPropertyValue(ChildMapEntryDefinitionParser.VALUE).getValue());
238 }
239 else
240 {
241 targetProperties.addPropertyValue(newName, bean.getBeanDefinition());
242 }
243 }
244 }
245 }
246
247 public void insertSingletonBeanInTarget(String propertyName, String singletonName)
248 {
249 String newName = bestGuessName(targetConfig, propertyName, target.getBeanClassName());
250
251 MutablePropertyValues targetProperties = target.getPropertyValues();
252 PropertyValue pv = targetProperties.getPropertyValue(newName);
253 Object oldValue = null == pv ? null : pv.getValue();
254
255 if (!targetConfig.isIgnored(propertyName))
256 {
257 if (targetConfig.isCollection(propertyName))
258 {
259 if (null == oldValue)
260 {
261 oldValue = new ManagedList();
262 pv = new PropertyValue(newName, oldValue);
263 targetProperties.addPropertyValue(pv);
264 }
265
266 List list = retrieveList(oldValue);
267 list.add(new RuntimeBeanReference(singletonName));
268 }
269 else
270 {
271
272 targetProperties.addPropertyValue(newName, new RuntimeBeanReference(singletonName));
273 }
274 }
275
276 }
277
278 protected void insertInTarget(String oldName){
279
280 }
281
282 protected static List retrieveList(Object value)
283 {
284 if (value instanceof List)
285 {
286 return (List) value;
287 }
288 else if (isDefinitionOf(value, MapCombiner.class))
289 {
290 return (List) unpackDefinition(value, MapCombiner.LIST);
291 }
292 else
293 {
294 throw new ClassCastException("Collection not of expected type: " + value);
295 }
296 }
297
298 private static Map retrieveMap(Object value)
299 {
300 if (value instanceof Map)
301 {
302 return (Map) value;
303 }
304 else if (isDefinitionOf(value, MapFactoryBean.class))
305 {
306 return (Map) unpackDefinition(value, "sourceMap");
307 }
308 else
309 {
310 throw new ClassCastException("Map not of expected type: " + value);
311 }
312 }
313
314 private static boolean isDefinitionOf(Object value, Class clazz)
315 {
316 return value instanceof BeanDefinition &&
317 ((BeanDefinition) value).getBeanClassName().equals(clazz.getName());
318 }
319
320 private static Object unpackDefinition(Object definition, String name)
321 {
322 return ((BeanDefinition) definition).getPropertyValues().getPropertyValue(name).getValue();
323 }
324
325
326
327
328
329
330
331
332
333
334 public void copyBeanToTarget()
335 {
336 logger.debug("copy " + bean.getBeanDefinition().getBeanClassName() + " -> " + target.getBeanClassName());
337 assertTargetPresent();
338 MutablePropertyValues targetProperties = target.getPropertyValues();
339 MutablePropertyValues beanProperties = bean.getBeanDefinition().getPropertyValues();
340 for (int i=0;i < beanProperties.size(); i++)
341 {
342 PropertyValue propertyValue = beanProperties.getPropertyValues()[i];
343 addPropertyWithoutReference(targetProperties, new SinglePropertyLiteral(),
344 propertyValue.getName(), propertyValue.getValue());
345 }
346 }
347
348 public void setBeanFlag(String flag)
349 {
350 MuleHierarchicalBeanDefinitionParserDelegate.setFlag(bean.getRawBeanDefinition(), flag);
351 }
352
353 protected void assertTargetPresent()
354 {
355 if (null == target)
356 {
357 throw new IllegalStateException("Bean assembler does not have a target");
358 }
359 }
360
361 protected void addPropertyWithReference(MutablePropertyValues properties, SingleProperty config,
362 String name, Object value)
363 {
364 if (!config.isIgnored())
365 {
366 if (config.isReference())
367 {
368 if (value instanceof String)
369 {
370 if (((String) value).trim().indexOf(" ") > -1)
371 {
372 config.setCollection();
373 }
374 for (StringTokenizer refs = new StringTokenizer((String) value); refs.hasMoreTokens();)
375 {
376 String ref = refs.nextToken();
377 if (logger.isDebugEnabled())
378 {
379 logger.debug("possible non-dependent reference: " + name + "/" + ref);
380 }
381 addPropertyWithoutReference(properties, config, name, new RuntimeBeanReference(ref));
382 }
383 }
384 else
385 {
386 throw new IllegalArgumentException("Bean reference must be a String: " + name + "/" + value);
387 }
388 }
389 else
390 {
391 addPropertyWithoutReference(properties, config, name, value);
392 }
393 }
394 }
395
396 protected void addPropertyWithoutReference(MutablePropertyValues properties, SingleProperty config,
397 String name, Object value)
398 {
399 if (!config.isIgnored())
400 {
401 if (logger.isDebugEnabled())
402 {
403 logger.debug(name + ": " + value);
404 }
405 Object oldValue = null;
406 if (properties.contains(name))
407 {
408 oldValue = properties.getPropertyValue(name).getValue();
409 }
410
411 if (config.isCollection() || oldValue instanceof Collection || value instanceof Collection)
412 {
413 Collection values = new ManagedList();
414 if (null != oldValue)
415 {
416 properties.removePropertyValue(name);
417 if (oldValue instanceof Collection)
418 {
419 values.addAll((Collection) oldValue);
420 }
421 else
422 {
423 values.add(oldValue);
424 }
425 }
426 if (value instanceof Collection)
427 {
428 values.addAll((Collection) value);
429 }
430 else
431 {
432 values.add(value);
433 }
434 properties.addPropertyValue(name, values);
435 }
436 else
437 {
438 properties.addPropertyValue(name, value);
439 }
440 }
441 }
442
443 protected static String bestGuessName(PropertyConfiguration config, String oldName, String className)
444 {
445 String newName = config.translateName(oldName);
446 if (! methodExists(className, newName))
447 {
448 String plural = newName + "s";
449 if (methodExists(className, plural))
450 {
451
452 config.addCollection(oldName);
453 return plural;
454 }
455 if (newName.endsWith("y"))
456 {
457 String pluraly = newName.substring(0, newName.length()-1) + "ies";
458 if (methodExists(className, pluraly))
459 {
460
461 config.addCollection(oldName);
462 return pluraly;
463 }
464 }
465 }
466 return newName;
467 }
468
469 protected static boolean methodExists(String className, String newName)
470 {
471 try
472 {
473
474
475
476
477 Class clazz = ClassUtils.getClass(className);
478 Method[] methods = clazz.getMethods();
479 String setter = "set" + newName;
480 for (int i = 0; i < methods.length; ++i)
481 {
482 if (methods[i].getName().equalsIgnoreCase(setter))
483 {
484 return true;
485 }
486 }
487 }
488 catch (Exception e)
489 {
490 logger.debug("Could not access bean class " + className, e);
491 }
492 return false;
493 }
494
495
496 }