View Javadoc

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