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