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