KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > config > schema > TestConfigObjectInvocationHandler


1 /**
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.config.schema;
5
6 import org.apache.commons.lang.StringUtils;
7 import org.apache.xmlbeans.XmlObject;
8 import org.apache.xmlbeans.impl.values.XmlObjectBase;
9
10 import com.tc.config.schema.dynamic.BooleanConfigItem;
11 import com.tc.config.schema.dynamic.ConfigItem;
12 import com.tc.config.schema.dynamic.ConfigItemListener;
13 import com.tc.config.schema.dynamic.FileConfigItem;
14 import com.tc.config.schema.dynamic.IntConfigItem;
15 import com.tc.config.schema.dynamic.ObjectArrayConfigItem;
16 import com.tc.config.schema.dynamic.StringArrayConfigItem;
17 import com.tc.config.schema.dynamic.StringConfigItem;
18 import com.tc.config.schema.dynamic.XPathBasedConfigItem;
19 import com.tc.logging.TCLogger;
20 import com.tc.logging.TCLogging;
21 import com.tc.util.Assert;
22
23 import java.io.File JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25 import java.lang.reflect.InvocationHandler JavaDoc;
26 import java.lang.reflect.InvocationTargetException JavaDoc;
27 import java.lang.reflect.Method JavaDoc;
28 import java.lang.reflect.Modifier JavaDoc;
29 import java.lang.reflect.Proxy JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.Map JavaDoc;
32
33 /**
34  * This class exists to avoid the massive pain of writing fully-compliant test versions of every single config object in
35  * the system. This is used by the {@link com.tc.config.schema.setup.TestTVSConfigurationSetupManagerFactory}; see
36  * there for more details.
37  * </p>
38  * <p>
39  * Basically, you can use this with the {@link java.util.Proxy} stuff and any random config interface (more
40  * specifically, one that has methods that all take no parameters and return instances of {@link ConfigItem}, or
41  * subinterfaces thereof), and you'll get back a config object that's special: when you call the normal methods that
42  * return config items, you can cast the returned item to a {@link com.tc.config.schema.SettableConfigItem}, and that
43  * will let you set its value. Note that doing anything else with the returned item, like trying to get its value or add
44  * or remove listeners, will just reward you with a {@link com.tc.util.TCAssertionError}.
45  * </p>
46  * <p>
47  * This class is messy (I am in a ridiculous rush right now to get this code down). The vast majority of its code is
48  * involved in taking a root XML bean and an XPath, and then descending through child beans &mdash; creating them along
49  * the way, if necessary &mdash; to
50  */

51 public class TestConfigObjectInvocationHandler implements InvocationHandler JavaDoc {
52
53   private static final TCLogger logger = TCLogging.getLogger(TestConfigObjectInvocationHandler.class);
54
55   /**
56    * This is the {@link ConfigItem} implementation we return. Feel free to add interfaces to this list as we create more
57    * typed subinterfaces of {@link ConfigItem}; the methods shouldn't do anything, just throw
58    * {@link com.tc.util.TCAssertionError}s.
59    */

60   private class OurSettableConfigItem implements SettableConfigItem, BooleanConfigItem, FileConfigItem, IntConfigItem,
61       ObjectArrayConfigItem, StringArrayConfigItem, StringConfigItem {
62     private final String JavaDoc xpath;
63
64     public OurSettableConfigItem(String JavaDoc xpath) {
65       this.xpath = xpath;
66     }
67
68     public synchronized void addListener(ConfigItemListener changeListener) {
69       throw Assert.failure("You can only set values on these items; you shouldn't actually be using them.");
70     }
71
72     public synchronized Object JavaDoc getObject() {
73       throw Assert.failure("You can only set values on these items; you shouldn't actually be using them.");
74     }
75
76     public synchronized void removeListener(ConfigItemListener changeListener) {
77       throw Assert.failure("You can only set values on these items; you shouldn't actually be using them.");
78     }
79
80     public synchronized void setValue(Object JavaDoc newValue) {
81       for (int i = 0; i < beansToSetOn.length; ++i) {
82         logger.debug("Setting value " + newValue + " on XPath '" + xpath + "' for bean " + beansToSetOn[i]);
83         setValueOnBean(newValue, beansToSetOn[i], this.xpath);
84       }
85     }
86
87     private String JavaDoc toMethodName(String JavaDoc xpathComponent) {
88       while (xpathComponent.startsWith("@"))
89         xpathComponent = xpathComponent.substring(1);
90
91       StringBuffer JavaDoc out = new StringBuffer JavaDoc();
92       char[] in = xpathComponent.toCharArray();
93       boolean capitalizeNext = true;
94
95       for (int i = 0; i < in.length; ++i) {
96         char ch = in[i];
97         if (ch == '-') capitalizeNext = true;
98         else {
99           out.append(capitalizeNext ? Character.toUpperCase(ch) : ch);
100           capitalizeNext = false;
101         }
102       }
103
104       return out.toString();
105     }
106
107     private void setValueOnBean(Object JavaDoc newValue, XmlObject beanToSetOn, String JavaDoc theXPath) {
108       synchronized (beanToSetOn) {
109         if (StringUtils.isBlank(theXPath)) {
110           logger.debug("Setting value " + newValue + " directly on bean " + beanToSetOn + ".");
111           setValueDirectly(newValue, beanToSetOn);
112         } else {
113           String JavaDoc remainingComponents = allButFirstComponentOf(theXPath);
114           String JavaDoc component = firstComponentOf(theXPath);
115
116           if (StringUtils.isBlank(remainingComponents)) {
117             // Special case, look for set...() method or xset...() method that takes an instance of our value type
118
if (setValueAsPropertyDirectly(beanToSetOn, component, newValue, "set")) return;
119             if (setValueAsPropertyDirectly(beanToSetOn, component, newValue, "xset")) return;
120           }
121
122           logger.debug("Looking for property '" + component + "' of bean " + beanToSetOn + ".");
123           XmlObject[] children = beanToSetOn.selectPath(component);
124
125           if (children == null || children.length == 0) {
126             // Create a new one
127
logger.debug("Property '" + component + "' doesn't exist; creating it.");
128             XmlObject newChild = createAndAddNewChild(beanToSetOn, component);
129             children = new XmlObject[] { newChild };
130           }
131
132           for (int i = 0; i < children.length; ++i) {
133             logger.debug("Setting value " + newValue + " on child " + (i + 1) + " of " + children.length + ".");
134             setValueOnBean(newValue, children[i], remainingComponents);
135           }
136         }
137       }
138     }
139
140     private XmlObject createAndAddNewChild(XmlObject beanToSetOn, String JavaDoc name) {
141       String JavaDoc asPropertyName = toMethodName(name);
142       Class JavaDoc beanClass = beanToSetOn.getClass();
143       Method JavaDoc creatorMethod = null;
144       String JavaDoc creatorMethodName = "addNew" + asPropertyName;
145
146       try {
147         logger.debug("Trying to create new child for property '" + name + "' on bean " + beanToSetOn + " of "
148                      + beanClass + ".");
149         creatorMethod = beanClass.getMethod(creatorMethodName, new Class JavaDoc[0]);
150         logger.debug("Found creator method " + creatorMethod);
151         Assert.eval(XmlObject.class.isAssignableFrom(creatorMethod.getReturnType()));
152         return (XmlObject) creatorMethod.invoke(beanToSetOn, new Object JavaDoc[0]);
153       } catch (NoSuchMethodException JavaDoc nsme) {
154         // leave it, try setting instead
155
logger.debug("Didn't find creator method named '" + creatorMethodName + "'");
156       } catch (IllegalArgumentException JavaDoc iae) {
157         throw Assert.failure("Can't invoke creator method " + creatorMethod, iae);
158       } catch (IllegalAccessException JavaDoc iae) {
159         throw Assert.failure("Can't invoke creator method " + creatorMethod, iae);
160       } catch (InvocationTargetException JavaDoc ite) {
161         throw Assert.failure("Can't invoke creator method " + creatorMethod, ite);
162       }
163
164       Method JavaDoc[] allMethods = beanClass.getMethods();
165       Method JavaDoc xsetMethod = null;
166       String JavaDoc methodName = "xset" + asPropertyName;
167       String JavaDoc factoryClassName = null;
168
169       try {
170         logger.debug("Looking for method named '" + methodName + "' instead.");
171         for (int i = 0; i < allMethods.length; ++i) {
172           Method JavaDoc thisMethod = allMethods[i];
173           if (thisMethod.getName().equals(methodName) && thisMethod.getReturnType().equals(Void.TYPE)
174               && thisMethod.getParameterTypes().length == 1
175               && XmlObject.class.isAssignableFrom(thisMethod.getParameterTypes()[0])) {
176             if (xsetMethod != null) {
177               // formatting
178
throw Assert.failure("There are multiple '" + methodName + "' methods in " + beanClass + "; one is "
179                                    + xsetMethod + ", and another is " + thisMethod + ".");
180             }
181             xsetMethod = thisMethod;
182           }
183         }
184
185         if (xsetMethod == null) {
186           // formatting
187
throw Assert.failure("There is no method named '" + methodName + "' in " + beanClass
188                                + ". If this method does exist, but on a subclass of " + beanClass
189                                + ", not on it itself, you may have specified the wrong XPath prefix when you created "
190                                + "this invocation handler.");
191         }
192         logger.debug("Found xset...() method: " + xsetMethod);
193
194         Class JavaDoc newObjectClass = xsetMethod.getParameterTypes()[0];
195         factoryClassName = newObjectClass.getName() + ".Factory";
196         logger.debug("Creating a new instance of " + newObjectClass + " using factory class '" + factoryClassName
197                      + "'.");
198         Class JavaDoc factoryClass = Class.forName(factoryClassName);
199         Method JavaDoc createMethod = factoryClass.getMethod("newInstance", new Class JavaDoc[0]);
200         Assert.eval(XmlObject.class.isAssignableFrom(createMethod.getReturnType()));
201         Assert.eval(Modifier.isStatic(createMethod.getModifiers()));
202         XmlObject out = (XmlObject) createMethod.invoke(null, null);
203         logger.debug("Created new object " + out + ".");
204         xsetMethod.invoke(beanToSetOn, new Object JavaDoc[] { out });
205         logger.debug("Set new object " + out + " via xset...() method " + xsetMethod + " on bean " + beanToSetOn);
206         return out;
207       } catch (ClassNotFoundException JavaDoc cnfe) {
208         throw Assert.failure("No factory class '" + factoryClassName + "'?", cnfe);
209       } catch (IllegalArgumentException JavaDoc iae) {
210         throw Assert.failure("Can't create instance using factory " + factoryClassName + " and assign using method "
211                              + xsetMethod + "?", iae);
212       } catch (IllegalAccessException JavaDoc iae) {
213         throw Assert.failure("Can't create instance using factory " + factoryClassName + " and assign using method "
214                              + xsetMethod + "?", iae);
215       } catch (InvocationTargetException JavaDoc ite) {
216         throw Assert.failure("Can't create instance using factory " + factoryClassName + " and assign using method "
217                              + xsetMethod + "?", ite);
218       } catch (SecurityException JavaDoc se) {
219         throw Assert.failure("Can't create instance using factory " + factoryClassName + " and assign using method "
220                              + xsetMethod + "?", se);
221       } catch (NoSuchMethodException JavaDoc nsme) {
222         throw Assert.failure("Can't create instance using factory " + factoryClassName + " and assign using method "
223                              + xsetMethod + "?", nsme);
224       }
225     }
226
227     private boolean assignmentCompatible(Class JavaDoc parameterType, Object JavaDoc actualObject) {
228       if (parameterType.isPrimitive()) {
229         if (parameterType.equals(Boolean.TYPE)) return actualObject instanceof Boolean JavaDoc;
230         if (parameterType.equals(Character.TYPE)) return actualObject instanceof Character JavaDoc;
231         if (parameterType.equals(Byte.TYPE)) return actualObject instanceof Byte JavaDoc;
232         if (parameterType.equals(Short.TYPE)) return actualObject instanceof Short JavaDoc;
233         if (parameterType.equals(Integer.TYPE)) return actualObject instanceof Integer JavaDoc;
234         if (parameterType.equals(Long.TYPE)) return actualObject instanceof Long JavaDoc;
235         if (parameterType.equals(Float.TYPE)) return actualObject instanceof Float JavaDoc;
236         if (parameterType.equals(Double.TYPE)) return actualObject instanceof Double JavaDoc;
237         throw Assert.failure("Unknown primitive type " + parameterType);
238       } else {
239         return actualObject == null || parameterType.isInstance(actualObject);
240       }
241     }
242
243     private boolean setValueAsPropertyDirectly(XmlObject onBean, String JavaDoc propertyName, Object JavaDoc newValue,
244                                                String JavaDoc prefixToTry) {
245       Method JavaDoc[] allMethods = onBean.getClass().getMethods();
246       String JavaDoc methodName = prefixToTry + toMethodName(propertyName);
247       Method JavaDoc setterMethod = null;
248
249       logger.debug("Looking for '" + methodName + "' method on " + onBean.getClass() + "...");
250       for (int i = 0; i < allMethods.length; ++i) {
251         if (allMethods[i].getName().equals(methodName) && allMethods[i].getParameterTypes().length == 1) {
252           if (setterMethod != null) {
253             // formatting
254
logger.debug("There are multiple '" + methodName + "' methods in " + onBean.getClass() + "; one is "
255                          + setterMethod + ", and another is " + allMethods[i] + ". Returning false.");
256             return false;
257           }
258
259           setterMethod = allMethods[i];
260         }
261       }
262
263       if (setterMethod == null) {
264         logger.debug("Can't find '" + methodName + "' method with one argument on " + onBean.getClass()
265                      + "; returning false.");
266         return false;
267       }
268
269       if (newValue == null && setterMethod.getParameterTypes()[0].isPrimitive()) {
270         // formatting
271
logger.debug("Unable to set null as a value on XML bean " + onBean + "; it requires a(n) "
272                      + setterMethod.getParameterTypes()[0] + ", which is a primitive type. Returning false.");
273         return false;
274       }
275
276       if (newValue != null && (!assignmentCompatible(setterMethod.getParameterTypes()[0], newValue))) {
277         // formatting
278
logger.debug("Unable to set value " + newValue + " on XML bean " + onBean + " via method " + setterMethod
279                      + "; it requires an object of " + setterMethod.getParameterTypes()[0] + ", and this value is of "
280                      + newValue.getClass() + " instead. Returning false.");
281         return false;
282       }
283
284       try {
285         logger.debug("Setting value " + newValue + " on " + onBean + " via method " + setterMethod + ".");
286         setterMethod.invoke(onBean, new Object JavaDoc[] { newValue });
287         return true;
288       } catch (IllegalArgumentException JavaDoc iae) {
289         throw Assert.failure("Unable to invoke " + setterMethod, iae);
290       } catch (IllegalAccessException JavaDoc iae) {
291         throw Assert.failure("Unable to invoke " + setterMethod, iae);
292       } catch (InvocationTargetException JavaDoc ite) {
293         throw Assert.failure("Unable to invoke " + setterMethod, ite);
294       }
295     }
296
297     private void setValueDirectly(Object JavaDoc newValue, XmlObject onBean) {
298       Method JavaDoc[] allMethods = onBean.getClass().getMethods();
299       Method JavaDoc setterMethod = null;
300       boolean isArray = newValue != null && newValue.getClass().isArray();
301       String JavaDoc searchDescrip = isArray ? "set...Array(...[])" : "set(...)";
302
303       logger.debug("Looking for " + searchDescrip + " method on " + onBean.getClass() + "...");
304       for (int i = 0; i < allMethods.length; ++i) {
305         if (isArray) {
306           if (allMethods[i].getName().startsWith("set") && allMethods[i].getName().endsWith("Array")
307               && allMethods[i].getParameterTypes().length == 1 && allMethods[i].getParameterTypes()[0].isArray()) {
308             if (setterMethod != null) {
309               // formatting
310
throw Assert.failure("There are multiple '" + searchDescrip + "' methods in " + onBean.getClass()
311                                    + "; one is " + setterMethod + ", and another is " + allMethods[i]);
312             }
313
314             setterMethod = allMethods[i];
315           }
316         } else {
317           Class JavaDoc declaringClass = allMethods[i].getDeclaringClass();
318           if (declaringClass.equals(XmlObject.class) || declaringClass.equals(XmlObjectBase.class)) continue;
319
320           if (allMethods[i].getName().equals("set") && allMethods[i].getParameterTypes().length == 1) {
321             if (setterMethod != null) {
322               // formatting
323
throw Assert.failure("There are multiple '" + searchDescrip + "' methods in " + onBean.getClass()
324                                    + "; one is " + setterMethod + ", and another is " + allMethods[i]);
325             }
326
327             setterMethod = allMethods[i];
328           }
329         }
330       }
331
332       if (setterMethod == null) throw Assert.failure("Can't find '" + searchDescrip + "' method with one argument on "
333                                                      + onBean.getClass() + ".");
334
335       if (newValue == null && setterMethod.getParameterTypes()[0].isPrimitive()) {
336         // formatting
337
throw Assert.failure("You can't set null as a value on XML bean " + onBean + "; it requires a(n) "
338                              + setterMethod.getParameterTypes()[0] + ", which is a primitive type.");
339       }
340
341       if (newValue != null && (!setterMethod.getParameterTypes()[0].isInstance(newValue))) {
342         // formatting
343
throw Assert.failure("You can't set value " + newValue + " on XML bean " + onBean + " via method "
344                              + setterMethod + "; it requires an object of " + setterMethod.getParameterTypes()[0]
345                              + ", and your value is of " + newValue.getClass() + " instead.");
346       }
347
348       try {
349         logger.debug("Setting value " + newValue + " on " + onBean + " via method " + setterMethod + ".");
350         setterMethod.invoke(onBean, new Object JavaDoc[] { newValue });
351       } catch (IllegalArgumentException JavaDoc iae) {
352         throw Assert.failure("Unable to invoke " + setterMethod, iae);
353       } catch (IllegalAccessException JavaDoc iae) {
354         throw Assert.failure("Unable to invoke " + setterMethod, iae);
355       } catch (InvocationTargetException JavaDoc ite) {
356         throw Assert.failure("Unable to invoke " + setterMethod, ite);
357       }
358     }
359
360     private String JavaDoc firstComponentOf(String JavaDoc theXPath) {
361       while (theXPath.startsWith("/"))
362         theXPath = theXPath.substring(1);
363       int index = theXPath.indexOf("/");
364       if (index < 0) return theXPath;
365       Assert.eval(index > 0);
366       String JavaDoc out = theXPath.substring(0, index);
367       while (out.startsWith("@"))
368         out = out.substring(1);
369       return out;
370     }
371
372     private String JavaDoc allButFirstComponentOf(String JavaDoc theXPath) {
373       while (theXPath.startsWith("/"))
374         theXPath = theXPath.substring(1);
375       int index = theXPath.indexOf("/");
376       if (index < 0) return null;
377       Assert.eval(index > 0);
378       return theXPath.substring(index + 1);
379     }
380
381     public void setValue(boolean newValue) {
382       setValue(new Boolean JavaDoc(newValue));
383     }
384
385     public void setValue(int newValue) {
386       setValue(new Integer JavaDoc(newValue));
387     }
388
389     public boolean getBoolean() {
390       return ((Boolean JavaDoc) getObject()).booleanValue();
391     }
392
393     public String JavaDoc getString() {
394       return (String JavaDoc) getObject();
395     }
396
397     public String JavaDoc[] getStringArray() {
398       return (String JavaDoc[]) getObject();
399     }
400
401     public File JavaDoc getFile() {
402       return (File JavaDoc) getObject();
403     }
404
405     public int getInt() {
406       return ((Integer JavaDoc) getObject()).intValue();
407     }
408
409     public Object JavaDoc[] getObjects() {
410       return (Object JavaDoc[]) getObject();
411     }
412   }
413
414   private final Class JavaDoc theInterface;
415   private final XmlObject[] beansToSetOn;
416   private final Object JavaDoc realImplementation;
417   private final String JavaDoc xpathPrefix;
418
419   private final Map JavaDoc configItems;
420
421   // The XPath prefix is because when we grab XPaths out of XPathBasedConfigItems, they're relative to the bean that
422
// that config object is based on, which might be a child of the one in the repository (using the ChildBeanRepository
423
// stuff). This path needs to be the XPath from the root of the repository to the bean used as the root of the config
424
// object.
425
public TestConfigObjectInvocationHandler(Class JavaDoc theInterface, XmlObject[] beansToSetOn, Object JavaDoc realImplementation,
426                                            String JavaDoc xpathPrefix) {
427     Assert.assertNotNull(theInterface);
428     Assert.assertNoNullElements(beansToSetOn);
429     Assert.assertNotNull(realImplementation);
430
431     Assert.eval(theInterface.isInstance(realImplementation));
432
433     this.theInterface = theInterface;
434     this.beansToSetOn = beansToSetOn;
435     this.realImplementation = realImplementation;
436     this.xpathPrefix = xpathPrefix;
437
438     this.configItems = new HashMap JavaDoc();
439   }
440
441   public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
442     Assert.assertNotNull(proxy);
443     Assert.assertNotNull(method);
444
445     // It's a getter method
446
if (ConfigItem.class.isAssignableFrom(method.getReturnType())) {
447       String JavaDoc propertyName = method.getName();
448       return itemForProperty(propertyName, method);
449     } else if (NewConfig.class.isAssignableFrom(method.getReturnType())) {
450       Object JavaDoc newRealObject = method.invoke(this.realImplementation, new Object JavaDoc[0]);
451       String JavaDoc subXPath = fetchSubXPathFor(method.getName());
452       String JavaDoc xpath;
453       if (xpathPrefix != null && subXPath != null) xpath = xpathPrefix + "/" + subXPath;
454       else if (xpathPrefix != null) xpath = xpathPrefix;
455       else xpath = subXPath;
456       System.err.println("Creating new sub-config object of " + method.getReturnType());
457       System.err.println("XPath: " + xpath);
458       System.err.println("New real object: " + newRealObject);
459       return Proxy.newProxyInstance(getClass().getClassLoader(), new Class JavaDoc[] { method.getReturnType() },
460                                     new TestConfigObjectInvocationHandler(method.getReturnType(), this.beansToSetOn,
461                                                                           newRealObject, xpath));
462     } else {
463       throw Assert.failure("This method, '" + method.getName() + "', has a return type of "
464                            + method.getReturnType().getName() + ", which isn't a descendant of ConfigItem. "
465                            + "We don't know how to support this for test config objects yet.");
466     }
467   }
468
469   private String JavaDoc fetchSubXPathFor(String JavaDoc methodName) {
470     String JavaDoc fieldName = camelToUnderscores(methodName) + "_SUB_XPATH";
471
472     try {
473       Field JavaDoc theField = this.realImplementation.getClass().getField(fieldName);
474       Assert.eval(Modifier.isPublic(theField.getModifiers()));
475       Assert.eval(Modifier.isStatic(theField.getModifiers()));
476       Assert.eval(Modifier.isFinal(theField.getModifiers()));
477       Assert.eval(String JavaDoc.class.equals(theField.getType()));
478       return (String JavaDoc) theField.get(null);
479     } catch (IllegalAccessException JavaDoc iae) {
480       throw Assert.failure("Can't fetch field '" + fieldName + "'?", iae);
481     } catch (NoSuchFieldException JavaDoc nsfe) {
482       return null;
483     }
484   }
485
486   private String JavaDoc camelToUnderscores(String JavaDoc methodName) {
487     StringBuffer JavaDoc out = new StringBuffer JavaDoc();
488     char[] source = methodName.toCharArray();
489     boolean lastWasLowercase = isLowercase(source[0]);
490     out.append(toUppercase(source[0]));
491
492     for (int i = 1; i < source.length; ++i) {
493       boolean thisIsLowercase = isLowercase(source[i]);
494
495       if (lastWasLowercase && (!thisIsLowercase)) {
496         // transition
497
out.append("_");
498       }
499
500       lastWasLowercase = thisIsLowercase;
501       out.append(toUppercase(source[i]));
502     }
503
504     return out.toString();
505   }
506
507   private boolean isLowercase(char ch) {
508     return Character.isLowerCase(ch);
509   }
510
511   private char toUppercase(char ch) {
512     return Character.toUpperCase(ch);
513   }
514
515   private synchronized OurSettableConfigItem itemForProperty(String JavaDoc propertyName, Method JavaDoc theMethod) {
516     OurSettableConfigItem out = (OurSettableConfigItem) this.configItems.get(propertyName);
517     if (out == null) {
518       try {
519         ConfigItem realItem = (ConfigItem) theMethod.invoke(realImplementation, new Object JavaDoc[0]);
520         Assert.eval("The base item we found was a " + realItem.getClass() + ", not an XPathBasedConfigItem",
521                     realItem instanceof XPathBasedConfigItem);
522
523         String JavaDoc effectiveXPath = (this.xpathPrefix == null ? "" : this.xpathPrefix + "/")
524                                 + ((XPathBasedConfigItem) realItem).xpath();
525         logger.debug("For property '" + propertyName + "' on proxied config-object implementation of interface "
526                      + this.theInterface.getName() + ", returning a config item with effective XPath '"
527                      + effectiveXPath + "'.");
528
529         out = new OurSettableConfigItem(effectiveXPath);
530         this.configItems.put(propertyName, out);
531       } catch (IllegalAccessException JavaDoc iae) {
532         throw Assert.failure("Unable to retrieve the real ConfigItem so we can get its XPath.", iae);
533       } catch (InvocationTargetException JavaDoc ite) {
534         throw Assert.failure("Unable to retrieve the real ConfigItem so we can get its XPath.", ite);
535       }
536     }
537     return out;
538   }
539
540 }
541
Popular Tags