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 private BeanDefinitionBuilder bean;
49 private PropertyConfiguration targetConfig;
50 private 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 private static List retrieveList(Object value)
248 {
249 if (value instanceof List)
250 {
251 return (List) value;
252 }
253 else if (isDefinitionOf(value, MapCombiner.class))
254 {
255 return (List) unpackDefinition(value, MapCombiner.LIST);
256 }
257 else
258 {
259 throw new ClassCastException("Collection not of expected type: " + value);
260 }
261 }
262
263 private static Map retrieveMap(Object value)
264 {
265 if (value instanceof Map)
266 {
267 return (Map) value;
268 }
269 else if (isDefinitionOf(value, MapFactoryBean.class))
270 {
271 return (Map) unpackDefinition(value, "sourceMap");
272 }
273 else
274 {
275 throw new ClassCastException("Map not of expected type: " + value);
276 }
277 }
278
279 private static boolean isDefinitionOf(Object value, Class clazz)
280 {
281 return value instanceof BeanDefinition &&
282 ((BeanDefinition) value).getBeanClassName().equals(clazz.getName());
283 }
284
285 private static Object unpackDefinition(Object definition, String name)
286 {
287 return ((BeanDefinition) definition).getPropertyValues().getPropertyValue(name).getValue();
288 }
289
290
291
292
293
294
295
296
297
298
299 public void copyBeanToTarget()
300 {
301 logger.debug("copy " + bean.getBeanDefinition().getBeanClassName() + " -> " + target.getBeanClassName());
302 assertTargetPresent();
303 MutablePropertyValues targetProperties = target.getPropertyValues();
304 MutablePropertyValues beanProperties = bean.getBeanDefinition().getPropertyValues();
305 for (int i=0;i < beanProperties.size(); i++)
306 {
307 PropertyValue propertyValue = beanProperties.getPropertyValues()[i];
308 addPropertyWithoutReference(targetProperties, new SinglePropertyLiteral(),
309 propertyValue.getName(), propertyValue.getValue());
310 }
311 }
312
313 public void setBeanFlag(String flag)
314 {
315 MuleHierarchicalBeanDefinitionParserDelegate.setFlag(bean.getRawBeanDefinition(), flag);
316 }
317
318 protected void assertTargetPresent()
319 {
320 if (null == target)
321 {
322 throw new IllegalStateException("Bean assembler does not have a target");
323 }
324 }
325
326 protected void addPropertyWithReference(MutablePropertyValues properties, SingleProperty config,
327 String name, Object value)
328 {
329 if (!config.isIgnored())
330 {
331 if (config.isReference())
332 {
333 if (value instanceof String)
334 {
335 if (((String) value).trim().indexOf(" ") > -1)
336 {
337 config.setCollection();
338 }
339 for (StringTokenizer refs = new StringTokenizer((String) value); refs.hasMoreTokens();)
340 {
341 String ref = refs.nextToken();
342 if (logger.isDebugEnabled())
343 {
344 logger.debug("possible non-dependent reference: " + name + "/" + ref);
345 }
346 addPropertyWithoutReference(properties, config, name, new RuntimeBeanReference(ref));
347 }
348 }
349 else
350 {
351 throw new IllegalArgumentException("Bean reference must be a String: " + name + "/" + value);
352 }
353 }
354 else
355 {
356 addPropertyWithoutReference(properties, config, name, value);
357 }
358 }
359 }
360
361 protected void addPropertyWithoutReference(MutablePropertyValues properties, SingleProperty config,
362 String name, Object value)
363 {
364 if (!config.isIgnored())
365 {
366 if (logger.isDebugEnabled())
367 {
368 logger.debug(name + ": " + value);
369 }
370 Object oldValue = null;
371 if (properties.contains(name))
372 {
373 oldValue = properties.getPropertyValue(name).getValue();
374 }
375
376 if (config.isCollection() || oldValue instanceof Collection || value instanceof Collection)
377 {
378 Collection values = new ManagedList();
379 if (null != oldValue)
380 {
381 properties.removePropertyValue(name);
382 if (oldValue instanceof Collection)
383 {
384 values.addAll((Collection) oldValue);
385 }
386 else
387 {
388 values.add(oldValue);
389 }
390 }
391 if (value instanceof Collection)
392 {
393 values.addAll((Collection) value);
394 }
395 else
396 {
397 values.add(value);
398 }
399 properties.addPropertyValue(name, values);
400 }
401 else
402 {
403 properties.addPropertyValue(name, value);
404 }
405 }
406 }
407
408 protected static String bestGuessName(PropertyConfiguration config, String oldName, String className)
409 {
410 String newName = config.translateName(oldName);
411 if (! methodExists(className, newName))
412 {
413 String plural = newName + "s";
414 if (methodExists(className, plural))
415 {
416
417 config.addCollection(oldName);
418 return plural;
419 }
420 if (newName.endsWith("y"))
421 {
422 String pluraly = newName.substring(0, newName.length()-1) + "ies";
423 if (methodExists(className, pluraly))
424 {
425
426 config.addCollection(oldName);
427 return pluraly;
428 }
429 }
430 }
431 return newName;
432 }
433
434 protected static boolean methodExists(String className, String newName)
435 {
436 try
437 {
438
439
440
441
442 Class clazz = ClassUtils.getClass(className);
443 Method[] methods = clazz.getMethods();
444 String setter = "set" + newName;
445 for (int i = 0; i < methods.length; ++i)
446 {
447 if (methods[i].getName().equalsIgnoreCase(setter))
448 {
449 return true;
450 }
451 }
452 }
453 catch (Exception e)
454 {
455 logger.debug("Could not access bean class " + className, e);
456 }
457 return false;
458 }
459
460 }