View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.jmx;
15  
16  import java.lang.reflect.Array;
17  import java.lang.reflect.Constructor;
18  import java.lang.reflect.InvocationTargetException;
19  import java.lang.reflect.Method;
20  import java.lang.reflect.Modifier;
21  import java.util.Enumeration;
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.MissingResourceException;
28  import java.util.ResourceBundle;
29  import java.util.Set;
30  
31  import javax.management.Attribute;
32  import javax.management.AttributeList;
33  import javax.management.AttributeNotFoundException;
34  import javax.management.DynamicMBean;
35  import javax.management.InvalidAttributeValueException;
36  import javax.management.MBeanAttributeInfo;
37  import javax.management.MBeanConstructorInfo;
38  import javax.management.MBeanException;
39  import javax.management.MBeanInfo;
40  import javax.management.MBeanNotificationInfo;
41  import javax.management.MBeanOperationInfo;
42  import javax.management.MBeanParameterInfo;
43  import javax.management.ObjectName;
44  import javax.management.ReflectionException;
45  import javax.management.modelmbean.ModelMBean;
46  
47  import org.eclipse.jetty.util.LazyList;
48  import org.eclipse.jetty.util.Loader;
49  import org.eclipse.jetty.util.TypeUtil;
50  import org.eclipse.jetty.util.log.Log;
51  
52  /* ------------------------------------------------------------ */
53  /** ObjectMBean.
54   * A dynamic MBean that can wrap an arbitary Object instance.
55   * the attributes and methods exposed by this bean are controlled by
56   * the merge of property bundles discovered by names related to all
57   * superclasses and all superinterfaces.
58   *
59   * Attributes and methods exported may be "Object" and must exist on the
60   * wrapped object, or "MBean" and must exist on a subclass of OBjectMBean
61   * or "MObject" which exists on the wrapped object, but whose values are
62   * converted to MBean object names.
63   *
64   */
65  public class ObjectMBean implements DynamicMBean
66  {
67      private static Class[] OBJ_ARG = new Class[]{Object.class};
68  
69      protected Object _managed;
70      private MBeanInfo _info;
71      private Map _getters=new HashMap();
72      private Map _setters=new HashMap();
73      private Map _methods=new HashMap();
74      private Set _convert=new HashSet();
75      private ClassLoader _loader;
76      private MBeanContainer _mbeanContainer;
77  
78      private static String OBJECT_NAME_CLASS = ObjectName.class.getName();
79      private static String OBJECT_NAME_ARRAY_CLASS = ObjectName[].class.getName();
80  
81      /* ------------------------------------------------------------ */
82      /**
83       * Create MBean for Object. Attempts to create an MBean for the object by searching the package
84       * and class name space. For example an object of the type
85       *
86       * <PRE>
87       * class com.acme.MyClass extends com.acme.util.BaseClass implements com.acme.Iface
88       * </PRE>
89       *
90       * Then this method would look for the following classes:
91       * <UL>
92       * <LI>com.acme.jmx.MyClassMBean
93       * <LI>com.acme.util.jmx.BaseClassMBean
94       * <LI>org.eclipse.jetty.jmx.ObjectMBean
95       * </UL>
96       *
97       * @param o The object
98       * @return A new instance of an MBean for the object or null.
99       */
100     public static Object mbeanFor(Object o)
101     {
102         try
103         {
104             Class oClass = o.getClass();
105             Object mbean = null;
106 
107             while (mbean == null && oClass != null)
108             {
109                 String pName = oClass.getPackage().getName();
110                 String cName = oClass.getName().substring(pName.length() + 1);
111                 String mName = pName + ".jmx." + cName + "MBean";
112                 
113 
114                 try
115                 {
116                     Class mClass = (Object.class.equals(oClass))?oClass=ObjectMBean.class:Loader.loadClass(oClass,mName,true);
117                     if (Log.isDebugEnabled())
118                         Log.debug("mbeanFor " + o + " mClass=" + mClass);
119 
120                     try
121                     {
122                         Constructor constructor = mClass.getConstructor(OBJ_ARG);
123                         mbean=constructor.newInstance(new Object[]{o});
124                     }
125                     catch(Exception e)
126                     {
127                         Log.ignore(e);
128                         if (ModelMBean.class.isAssignableFrom(mClass))
129                         {
130                             mbean=mClass.newInstance();
131                             ((ModelMBean)mbean).setManagedResource(o, "objectReference");
132                         }
133                     }
134 
135                     if (Log.isDebugEnabled())
136                         Log.debug("mbeanFor " + o + " is " + mbean);
137                     return mbean;
138                 }
139                 catch (ClassNotFoundException e)
140                 {
141                     if (e.toString().endsWith("MBean"))
142                         Log.ignore(e);
143                     else
144                         Log.warn(e);
145                 }
146                 catch (Error e)
147                 {
148                     Log.warn(e);
149                     mbean = null;
150                 }
151                 catch (Exception e)
152                 {
153                     Log.warn(e);
154                     mbean = null;
155                 }
156 
157                 oClass = oClass.getSuperclass();
158             }
159         }
160         catch (Exception e)
161         {
162             Log.ignore(e);
163         }
164         return null;
165     }
166 
167 
168     public ObjectMBean(Object managedObject)
169     {
170         _managed = managedObject;
171         _loader = Thread.currentThread().getContextClassLoader();
172     }
173     
174     public Object getManagedObject()
175     {
176         return _managed;
177     }
178     
179     public ObjectName getObjectName()
180     {
181         return null;
182     }
183     
184     public String getObjectNameBasis()
185     {
186         return null;
187     }
188 
189     protected void setMBeanContainer(MBeanContainer container)
190     {
191        this._mbeanContainer = container;
192     }
193 
194     public MBeanContainer getMBeanContainer ()
195     {
196         return this._mbeanContainer;
197     }
198     
199     
200     public MBeanInfo getMBeanInfo()
201     {
202         try
203         {
204             if (_info==null)
205             {
206                 // Start with blank lazy lists attributes etc.
207                 String desc=null;
208                 Object attributes=null;
209                 Object constructors=null;
210                 Object operations=null;
211                 Object notifications=null;
212 
213                 // Find list of classes that can influence the mbean
214                 Class o_class=_managed.getClass();
215                 Object influences = findInfluences(null, _managed.getClass());
216 
217                 // Set to record defined items
218                 Set defined=new HashSet();
219 
220                 // For each influence
221                 for (int i=0;i<LazyList.size(influences);i++)
222                 {
223                     Class oClass = (Class)LazyList.get(influences, i);
224 
225                     // look for a bundle defining methods
226                     if (Object.class.equals(oClass))
227                         oClass=ObjectMBean.class;
228                     String pName = oClass.getPackage().getName();
229                     String cName = oClass.getName().substring(pName.length() + 1);
230                     String rName = pName.replace('.', '/') + "/jmx/" + cName+"-mbean";
231 
232                     try
233                     {
234                         Log.debug(rName);
235                         ResourceBundle bundle = Loader.getResourceBundle(o_class, rName,true,Locale.getDefault());
236 
237                         
238                         // Extract meta data from bundle
239                         Enumeration e = bundle.getKeys();
240                         while (e.hasMoreElements())
241                         {
242                             String key = (String)e.nextElement();
243                             String value = bundle.getString(key);
244 
245                             // Determin if key is for mbean , attribute or for operation
246                             if (key.equals(cName))
247                             {
248                                 // set the mbean description
249                                 if (desc==null)
250                                     desc=value;
251                             }
252                             else if (key.indexOf('(')>0)
253                             {
254                                 // define an operation
255                                 if (!defined.contains(key) && key.indexOf('[')<0)
256                                 {
257                                     defined.add(key);
258                                     operations=LazyList.add(operations,defineOperation(key, value, bundle));
259                                 }
260                             }
261                             else
262                             {
263                                 // define an attribute
264                                 if (!defined.contains(key))
265                                 {
266                                     defined.add(key);
267                                     attributes=LazyList.add(attributes,defineAttribute(key, value));
268                                 }
269                             }
270                         }
271 
272                     }
273                     catch(MissingResourceException e)
274                     {
275                         Log.ignore(e);
276                     }
277                 }
278 
279                 _info = new MBeanInfo(o_class.getName(),
280                                 desc,
281                                 (MBeanAttributeInfo[])LazyList.toArray(attributes, MBeanAttributeInfo.class),
282                                 (MBeanConstructorInfo[])LazyList.toArray(constructors, MBeanConstructorInfo.class),
283                                 (MBeanOperationInfo[])LazyList.toArray(operations, MBeanOperationInfo.class),
284                                 (MBeanNotificationInfo[])LazyList.toArray(notifications, MBeanNotificationInfo.class));
285             }
286         }
287         catch(RuntimeException e)
288         {
289             Log.warn(e);
290             throw e;
291         }
292         return _info;
293     }
294 
295 
296     /* ------------------------------------------------------------ */
297     public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException
298     {
299         Method getter = (Method) _getters.get(name);
300         if (getter == null)
301             throw new AttributeNotFoundException(name);
302         try
303         {
304             Object o = _managed;
305             if (getter.getDeclaringClass().isInstance(this))
306                 o = this; // mbean method
307 
308             // get the attribute
309             Object r=getter.invoke(o, (java.lang.Object[]) null);
310 
311             // convert to ObjectName if need be.
312             if (r!=null && _convert.contains(name))
313             {
314                 if (r.getClass().isArray())
315                 {
316                     ObjectName[] on = new ObjectName[Array.getLength(r)];
317                     for (int i=0;i<on.length;i++)
318                         on[i]=_mbeanContainer.findMBean(Array.get(r, i));
319                     r=on;
320                 }
321                 else
322                 {
323                     ObjectName mbean = _mbeanContainer.findMBean(r);
324                     if (mbean==null)
325                         return null;
326                     r=mbean;
327                 }
328             }
329             return r;
330         }
331         catch (IllegalAccessException e)
332         {
333             Log.warn(Log.EXCEPTION, e);
334             throw new AttributeNotFoundException(e.toString());
335         }
336         catch (InvocationTargetException e)
337         {
338             Log.warn(Log.EXCEPTION, e);
339             throw new ReflectionException((Exception) e.getTargetException());
340         }
341     }
342 
343     /* ------------------------------------------------------------ */
344     public AttributeList getAttributes(String[] names)
345     {
346         AttributeList results = new AttributeList(names.length);
347         for (int i = 0; i < names.length; i++)
348         {
349             try
350             {
351                 results.add(new Attribute(names[i], getAttribute(names[i])));
352             }
353             catch (Exception e)
354             {
355                 Log.warn(Log.EXCEPTION, e);
356             }
357         }
358         return results;
359     }
360 
361     /* ------------------------------------------------------------ */
362     public void setAttribute(Attribute attr) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException
363     {
364         if (attr == null)
365             return;
366 
367         if (Log.isDebugEnabled())
368             Log.debug("setAttribute " + _managed + ":" +attr.getName() + "=" + attr.getValue());
369         Method setter = (Method) _setters.get(attr.getName());
370         if (setter == null)
371             throw new AttributeNotFoundException(attr.getName());
372         try
373         {
374             Object o = _managed;
375             if (setter.getDeclaringClass().isInstance(this))
376                 o = this;
377 
378             // get the value
379             Object value = attr.getValue();
380 
381             // convert from ObjectName if need be
382             if (value!=null && _convert.contains(attr.getName()))
383             {
384                 if (value.getClass().isArray())
385                 {
386                     Class t=setter.getParameterTypes()[0].getComponentType();
387                     Object na = Array.newInstance(t,Array.getLength(value));
388                     for (int i=Array.getLength(value);i-->0;)
389                         Array.set(na, i, _mbeanContainer.findBean((ObjectName)Array.get(value, i)));
390                     value=na;
391                 }
392                 else
393                     value=_mbeanContainer.findBean((ObjectName)value);
394             }
395 
396             // do the setting
397             setter.invoke(o, new Object[]{ value });
398         }
399         catch (IllegalAccessException e)
400         {
401             Log.warn(Log.EXCEPTION, e);
402             throw new AttributeNotFoundException(e.toString());
403         }
404         catch (InvocationTargetException e)
405         {
406             Log.warn(Log.EXCEPTION, e);
407             throw new ReflectionException((Exception) e.getTargetException());
408         }
409     }
410 
411     /* ------------------------------------------------------------ */
412     public AttributeList setAttributes(AttributeList attrs)
413     {
414         Log.debug("setAttributes");
415 
416         AttributeList results = new AttributeList(attrs.size());
417         Iterator iter = attrs.iterator();
418         while (iter.hasNext())
419         {
420             try
421             {
422                 Attribute attr = (Attribute) iter.next();
423                 setAttribute(attr);
424                 results.add(new Attribute(attr.getName(), getAttribute(attr.getName())));
425             }
426             catch (Exception e)
427             {
428                 Log.warn(Log.EXCEPTION, e);
429             }
430         }
431         return results;
432     }
433 
434     /* ------------------------------------------------------------ */
435     public Object invoke(String name, Object[] params, String[] signature) throws MBeanException, ReflectionException
436     {
437         if (Log.isDebugEnabled())
438             Log.debug("invoke " + name);
439 
440         String methodKey = name + "(";
441         if (signature != null)
442             for (int i = 0; i < signature.length; i++)
443                 methodKey += (i > 0 ? "," : "") + signature[i];
444         methodKey += ")";
445 
446         ClassLoader old_loader=Thread.currentThread().getContextClassLoader();
447         try
448         {
449             Thread.currentThread().setContextClassLoader(_loader);
450             Method method = (Method) _methods.get(methodKey);
451             if (method == null)
452                 throw new NoSuchMethodException(methodKey);
453 
454             Object o = _managed;
455             if (method.getDeclaringClass().isInstance(this))
456                 o = this;
457             return method.invoke(o, params);
458         }
459         catch (NoSuchMethodException e)
460         {
461             Log.warn(Log.EXCEPTION, e);
462             throw new ReflectionException(e);
463         }
464         catch (IllegalAccessException e)
465         {
466             Log.warn(Log.EXCEPTION, e);
467             throw new MBeanException(e);
468         }
469         catch (InvocationTargetException e)
470         {
471             Log.warn(Log.EXCEPTION, e);
472             throw new ReflectionException((Exception) e.getTargetException());
473         }
474         finally
475         {
476             Thread.currentThread().setContextClassLoader(old_loader);
477         }
478     }
479 
480     private static Object findInfluences(Object influences, Class aClass)
481     {
482         if (aClass!=null)
483         {
484             // This class is an influence
485             influences=LazyList.add(influences,aClass);
486 
487             // So are the super classes
488             influences=findInfluences(influences,aClass.getSuperclass());
489 
490             // So are the interfaces
491             Class[] ifs = aClass.getInterfaces();
492             for (int i=0;ifs!=null && i<ifs.length;i++)
493                 influences=findInfluences(influences,ifs[i]);
494         }
495         return influences;
496     }
497 
498     /* ------------------------------------------------------------ */
499     /**
500      * Define an attribute on the managed object. The meta data is defined by looking for standard
501      * getter and setter methods. Descriptions are obtained with a call to findDescription with the
502      * attribute name.
503      *
504      * @param name
505      * @param metaData "description" or "access:description" or "type:access:description"  where type is
506      * one of: <ul>
507      * <li>"Object" The field/method is on the managed object.
508      * <li>"MBean" The field/method is on the mbean proxy object
509      * <li>"MObject" The field/method is on the managed object and value should be converted to MBean reference
510      * <li>"MMBean" The field/method is on the mbean proxy object and value should be converted to MBean reference
511      * </ul>
512      * the access is either "RW" or "RO".
513      */
514     public MBeanAttributeInfo defineAttribute(String name, String metaData)
515     {
516         String description = "";
517         boolean writable = true;
518         boolean onMBean = false;
519         boolean convert = false;
520 
521         if (metaData!= null)
522         {
523             String[] tokens = metaData.split(":", 3);
524             for (int t=0;t<tokens.length-1;t++)
525             {
526                 tokens[t]=tokens[t].trim();
527                 if ("RO".equals(tokens[t]))
528                     writable=false;
529                 else 
530                 {
531                     onMBean=("MMBean".equalsIgnoreCase(tokens[t]) || "MBean".equalsIgnoreCase(tokens[t]));
532                     convert=("MMBean".equalsIgnoreCase(tokens[t]) || "MObject".equalsIgnoreCase(tokens[t]));
533                 }
534             }
535             description=tokens[tokens.length-1];
536         }
537         
538 
539         String uName = name.substring(0, 1).toUpperCase() + name.substring(1);
540         Class oClass = onMBean ? this.getClass() : _managed.getClass();
541 
542         if (Log.isDebugEnabled())
543             Log.debug("defineAttribute "+name+" "+onMBean+":"+writable+":"+oClass+":"+description);
544 
545         Class type = null;
546         Method getter = null;
547         Method setter = null;
548         Method[] methods = oClass.getMethods();
549         for (int m = 0; m < methods.length; m++)
550         {
551             if ((methods[m].getModifiers() & Modifier.PUBLIC) == 0)
552                 continue;
553 
554             // Look for a getter
555             if (methods[m].getName().equals("get" + uName) && methods[m].getParameterTypes().length == 0)
556             {
557                 if (getter != null)
558                     throw new IllegalArgumentException("Multiple getters for attr " + name+ " in "+oClass);
559                 getter = methods[m];
560                 if (type != null && !type.equals(methods[m].getReturnType()))
561                     throw new IllegalArgumentException("Type conflict for attr " + name+ " in "+oClass);
562                 type = methods[m].getReturnType();
563             }
564 
565             // Look for an is getter
566             if (methods[m].getName().equals("is" + uName) && methods[m].getParameterTypes().length == 0)
567             {
568                 if (getter != null)
569                     throw new IllegalArgumentException("Multiple getters for attr " + name+ " in "+oClass);
570                 getter = methods[m];
571                 if (type != null && !type.equals(methods[m].getReturnType()))
572                     throw new IllegalArgumentException("Type conflict for attr " + name+ " in "+oClass);
573                 type = methods[m].getReturnType();
574             }
575 
576             // look for a setter
577             if (writable && methods[m].getName().equals("set" + uName) && methods[m].getParameterTypes().length == 1)
578             {
579                 if (setter != null)
580                     throw new IllegalArgumentException("Multiple setters for attr " + name+ " in "+oClass);
581                 setter = methods[m];
582                 if (type != null && !type.equals(methods[m].getParameterTypes()[0]))
583                     throw new IllegalArgumentException("Type conflict for attr " + name+ " in "+oClass);
584                 type = methods[m].getParameterTypes()[0];
585             }
586         }
587         
588         if (convert)
589         {
590             if (type==null)
591                 throw new IllegalArgumentException("No type for " + name+" on "+_managed.getClass());
592                 
593             if (type.isPrimitive() && !type.isArray())
594                 throw new IllegalArgumentException("Cannot convert primative " + name);
595         }
596 
597         if (getter == null && setter == null)
598             throw new IllegalArgumentException("No getter or setters found for " + name+ " in "+oClass);
599 
600         try
601         {
602             // Remember the methods
603             _getters.put(name, getter);
604             _setters.put(name, setter);
605 
606 
607 
608             MBeanAttributeInfo info=null;
609             if (convert)
610             {
611                 _convert.add(name);
612                 if (type.isArray())
613                     info= new MBeanAttributeInfo(name,OBJECT_NAME_ARRAY_CLASS,description,getter!=null,setter!=null,getter!=null&&getter.getName().startsWith("is"));
614 
615                 else
616                     info= new MBeanAttributeInfo(name,OBJECT_NAME_CLASS,description,getter!=null,setter!=null,getter!=null&&getter.getName().startsWith("is"));
617             }
618             else
619                 info= new MBeanAttributeInfo(name,description,getter,setter);
620 
621             return info;
622         }
623         catch (Exception e)
624         {
625             Log.warn(Log.EXCEPTION, e);
626             throw new IllegalArgumentException(e.toString());
627         }
628     }
629 
630 
631     /* ------------------------------------------------------------ */
632     /**
633      * Define an operation on the managed object. Defines an operation with parameters. Refection is
634      * used to determine find the method and it's return type. The description of the method is
635      * found with a call to findDescription on "name(signature)". The name and description of each
636      * parameter is found with a call to findDescription with "name(signature)[n]", the returned
637      * description is for the last parameter of the partial signature and is assumed to start with
638      * the parameter name, followed by a colon.
639      *
640      * @param metaData "description" or "impact:description" or "type:impact:description", type is
641      * the "Object","MBean", "MMBean" or "MObject" to indicate the method is on the object, the MBean or on the
642      * object but converted to an MBean reference, and impact is either "ACTION","INFO","ACTION_INFO" or "UNKNOWN".
643      */
644     private MBeanOperationInfo defineOperation(String signature, String metaData, ResourceBundle bundle)
645     {
646         String[] tokens=metaData.split(":",3);
647         int i=tokens.length-1;
648         String description=tokens[i--];
649         String impact_name = i<0?"UNKNOWN":tokens[i--].trim();
650         if (i==0)
651             tokens[0]=tokens[0].trim();
652         boolean onMBean= i==0 && ("MBean".equalsIgnoreCase(tokens[0])||"MMBean".equalsIgnoreCase(tokens[0]));
653         boolean convert= i==0 && ("MObject".equalsIgnoreCase(tokens[0])||"MMBean".equalsIgnoreCase(tokens[0]));
654 
655         if (Log.isDebugEnabled())
656             Log.debug("defineOperation "+signature+" "+onMBean+":"+impact_name+":"+description);
657 
658         Class oClass = onMBean ? this.getClass() : _managed.getClass();
659 
660         try
661         {
662             // Resolve the impact
663             int impact=MBeanOperationInfo.UNKNOWN;
664             if (impact_name==null || impact_name.equals("UNKNOWN"))
665                 impact=MBeanOperationInfo.UNKNOWN;
666             else if (impact_name.equals("ACTION"))
667                 impact=MBeanOperationInfo.ACTION;
668             else if (impact_name.equals("INFO"))
669                 impact=MBeanOperationInfo.INFO;
670             else if (impact_name.equals("ACTION_INFO"))
671                 impact=MBeanOperationInfo.ACTION_INFO;
672             else
673                 Log.warn("Unknown impact '"+impact_name+"' for "+signature);
674 
675 
676             // split the signature
677             String[] parts=signature.split("[\\(\\)]");
678             String method_name=parts[0];
679             String arguments=parts.length==2?parts[1]:null;
680             String[] args=arguments==null?new String[0]:arguments.split(" *, *");
681 
682             // Check types and normalize signature.
683             Class[] types = new Class[args.length];
684             MBeanParameterInfo[] pInfo = new MBeanParameterInfo[args.length];
685             signature=method_name;
686             for (i = 0; i < args.length; i++)
687             {
688                 Class type = TypeUtil.fromName(args[i]);
689                 if (type == null)
690                     type = Thread.currentThread().getContextClassLoader().loadClass(args[i]);
691                 types[i] = type;
692                 args[i] = type.isPrimitive() ? TypeUtil.toName(type) : args[i];
693                 signature+=(i>0?",":"(")+args[i];
694             }
695             signature+=(i>0?")":"()");
696 
697             // Build param infos
698             for (i = 0; i < args.length; i++)
699             {
700                 String param_desc = bundle.getString(signature + "[" + i + "]");
701                 parts=param_desc.split(" *: *",2);
702                 if (Log.isDebugEnabled())
703                     Log.debug(parts[0]+": "+parts[1]);
704                 pInfo[i] = new MBeanParameterInfo(parts[0].trim(), args[i], parts[1].trim());
705             }
706 
707             // build the operation info
708             Method method = oClass.getMethod(method_name, types);
709             Class returnClass = method.getReturnType();
710             _methods.put(signature, method);
711             if (convert)
712                 _convert.add(signature);
713 
714             return new MBeanOperationInfo(method_name, description, pInfo, returnClass.isPrimitive() ? TypeUtil.toName(returnClass) : (returnClass.getName()), impact);
715         }
716         catch (Exception e)
717         {
718             Log.warn("Operation '"+signature+"'", e);
719             throw new IllegalArgumentException(e.toString());
720         }
721 
722     }
723 
724 }