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