1// 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} 778