jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java
changeset 834 dc74d4ddc28e
parent 715 f16baef3a20e
parent 833 bfa2bef7517c
child 1221 e3dc70e4e610
equal deleted inserted replaced
832:5484c7a35278 834:dc74d4ddc28e
    34 import java.lang.reflect.InvocationTargetException;
    34 import java.lang.reflect.InvocationTargetException;
    35 import java.lang.reflect.Method;
    35 import java.lang.reflect.Method;
    36 import java.lang.reflect.Type;
    36 import java.lang.reflect.Type;
    37 import java.util.Arrays;
    37 import java.util.Arrays;
    38 import java.util.List;
    38 import java.util.List;
       
    39 import java.util.Map;
    39 import java.util.WeakHashMap;
    40 import java.util.WeakHashMap;
       
    41 import javax.management.Description;
    40 
    42 
    41 import javax.management.Descriptor;
    43 import javax.management.Descriptor;
    42 import javax.management.ImmutableDescriptor;
    44 import javax.management.ImmutableDescriptor;
    43 import javax.management.IntrospectionException;
    45 import javax.management.IntrospectionException;
    44 import javax.management.InvalidAttributeValueException;
    46 import javax.management.InvalidAttributeValueException;
       
    47 import javax.management.MBean;
    45 import javax.management.MBeanAttributeInfo;
    48 import javax.management.MBeanAttributeInfo;
    46 import javax.management.MBeanConstructorInfo;
    49 import javax.management.MBeanConstructorInfo;
    47 import javax.management.MBeanException;
    50 import javax.management.MBeanException;
    48 import javax.management.MBeanInfo;
    51 import javax.management.MBeanInfo;
    49 import javax.management.MBeanNotificationInfo;
    52 import javax.management.MBeanNotificationInfo;
    50 import javax.management.MBeanOperationInfo;
    53 import javax.management.MBeanOperationInfo;
       
    54 import javax.management.MXBean;
       
    55 import javax.management.ManagedAttribute;
       
    56 import javax.management.ManagedOperation;
    51 import javax.management.NotCompliantMBeanException;
    57 import javax.management.NotCompliantMBeanException;
    52 import javax.management.NotificationBroadcaster;
    58 import javax.management.NotificationBroadcaster;
       
    59 import javax.management.NotificationInfo;
       
    60 import javax.management.NotificationInfos;
    53 import javax.management.ReflectionException;
    61 import javax.management.ReflectionException;
    54 
    62 
    55 /**
    63 /**
    56  * An introspector for MBeans of a certain type.  There is one instance
    64  * An introspector for MBeans of a certain type.  There is one instance
    57  * of this class for Standard MBeans, and one for every MXBeanMappingFactory;
    65  * of this class for Standard MBeans, and one for every MXBeanMappingFactory;
   151      * may be null.
   159      * may be null.
   152      */
   160      */
   153     abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
   161     abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
   154             M getter, M setter) throws IntrospectionException;
   162             M getter, M setter) throws IntrospectionException;
   155 
   163 
       
   164     final String getAttributeDescription(
       
   165             String attributeName, String defaultDescription,
       
   166             Method getter, Method setter) throws IntrospectionException {
       
   167         String g = Introspector.descriptionForElement(getter);
       
   168         String s = Introspector.descriptionForElement(setter);
       
   169         if (g == null) {
       
   170             if (s == null)
       
   171                 return defaultDescription;
       
   172             else
       
   173                 return s;
       
   174         } else if (s == null || g.equals(s)) {
       
   175             return g;
       
   176         } else {
       
   177             throw new IntrospectionException(
       
   178                     "Inconsistent @Description on getter and setter for " +
       
   179                     "attribute " + attributeName);
       
   180         }
       
   181     }
       
   182 
   156     /**
   183     /**
   157      * Construct an MBeanOperationInfo for the given operation based on
   184      * Construct an MBeanOperationInfo for the given operation based on
   158      * the M it was derived from.
   185      * the M it was derived from.
   159      */
   186      */
   160     abstract MBeanOperationInfo getMBeanOperationInfo(String operationName,
   187     abstract MBeanOperationInfo getMBeanOperationInfo(String operationName,
   182     Descriptor getSpecificMBeanDescriptor() {
   209     Descriptor getSpecificMBeanDescriptor() {
   183         return ImmutableDescriptor.EMPTY_DESCRIPTOR;
   210         return ImmutableDescriptor.EMPTY_DESCRIPTOR;
   184     }
   211     }
   185 
   212 
   186     void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
   213     void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
   187         if (!mbeanType.isInterface()) {
   214         if (!mbeanType.isInterface() &&
   188             throw new NotCompliantMBeanException("Not an interface: " +
   215                 !mbeanType.isAnnotationPresent(MBean.class) &&
       
   216                 !Introspector.hasMXBeanAnnotation(mbeanType)) {
       
   217             throw new NotCompliantMBeanException("Not an interface and " +
       
   218                     "does not have @" + MBean.class.getSimpleName() +
       
   219                     " or @" + MXBean.class.getSimpleName() + " annotation: " +
   189                     mbeanType.getName());
   220                     mbeanType.getName());
   190         }
   221         }
   191     }
   222     }
   192 
   223 
   193     /**
   224     /**
   194      * Get the methods to be analyzed to build the MBean interface.
   225      * Get the methods to be analyzed to build the MBean interface.
   195      */
   226      */
   196     List<Method> getMethods(final Class<?> mbeanType) throws Exception {
   227     List<Method> getMethods(final Class<?> mbeanType) throws Exception {
   197         return Arrays.asList(mbeanType.getMethods());
   228         if (mbeanType.isInterface())
       
   229             return Arrays.asList(mbeanType.getMethods());
       
   230 
       
   231         final List<Method> methods = newList();
       
   232         getAnnotatedMethods(mbeanType, methods);
       
   233         return methods;
   198     }
   234     }
   199 
   235 
   200     final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
   236     final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
   201     throws NotCompliantMBeanException {
   237     throws NotCompliantMBeanException {
   202         PerInterfaceMap<M> map = getPerInterfaceMap();
   238         PerInterfaceMap<M> map = getPerInterfaceMap();
   230      */
   266      */
   231     private MBeanInfo makeInterfaceMBeanInfo(Class<?> mbeanInterface,
   267     private MBeanInfo makeInterfaceMBeanInfo(Class<?> mbeanInterface,
   232             MBeanAnalyzer<M> analyzer) throws IntrospectionException {
   268             MBeanAnalyzer<M> analyzer) throws IntrospectionException {
   233         final MBeanInfoMaker maker = new MBeanInfoMaker();
   269         final MBeanInfoMaker maker = new MBeanInfoMaker();
   234         analyzer.visit(maker);
   270         analyzer.visit(maker);
   235         final String description =
   271         final String defaultDescription =
   236                 "Information on the management interface of the MBean";
   272                 "Information on the management interface of the MBean";
       
   273         String description = Introspector.descriptionForElement(mbeanInterface);
       
   274         if (description == null)
       
   275             description = defaultDescription;
   237         return maker.makeMBeanInfo(mbeanInterface, description);
   276         return maker.makeMBeanInfo(mbeanInterface, description);
   238     }
   277     }
   239 
   278 
   240     /** True if the given getter and setter are consistent. */
   279     /** True if the given getter and setter are consistent. */
   241     final boolean consistent(M getter, M setter) {
   280     final boolean consistent(M getter, M setter) {
   405      */
   444      */
   406     final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface)
   445     final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface)
   407     throws NotCompliantMBeanException {
   446     throws NotCompliantMBeanException {
   408         MBeanInfo mbi =
   447         MBeanInfo mbi =
   409                 getClassMBeanInfo(resource.getClass(), perInterface);
   448                 getClassMBeanInfo(resource.getClass(), perInterface);
   410         MBeanNotificationInfo[] notifs = findNotifications(resource);
   449         MBeanNotificationInfo[] notifs;
       
   450         try {
       
   451             notifs = findNotifications(resource);
       
   452         } catch (RuntimeException e) {
       
   453             NotCompliantMBeanException x =
       
   454                     new NotCompliantMBeanException(e.getMessage());
       
   455             x.initCause(e);
       
   456             throw x;
       
   457         }
   411         Descriptor d = getSpecificMBeanDescriptor();
   458         Descriptor d = getSpecificMBeanDescriptor();
   412         boolean anyNotifs = (notifs != null && notifs.length > 0);
   459         boolean anyNotifs = (notifs != null && notifs.length > 0);
   413         if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
   460         if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
   414             return mbi;
   461             return mbi;
   415         else {
   462         else {
   458             }
   505             }
   459             return mbi;
   506             return mbi;
   460         }
   507         }
   461     }
   508     }
   462 
   509 
       
   510     /*
       
   511      * Add to "methods" every public method that has the @ManagedAttribute
       
   512      * or @ManagedOperation annotation, in the given class or any of
       
   513      * its superclasses or superinterfaces.
       
   514      *
       
   515      * We always add superclass or superinterface methods first, so that
       
   516      * the stable sort used by eliminateCovariantMethods will put the
       
   517      * method from the most-derived class last.  This means that we will
       
   518      * see the version of the @ManagedAttribute (or ...Operation) annotation
       
   519      * from that method, which might have a different description or whatever.
       
   520      */
       
   521     private static void getAnnotatedMethods(Class<?> c, List<Method> methods)
       
   522     throws Exception {
       
   523         Class<?> sup = c.getSuperclass();
       
   524         if (sup != null)
       
   525             getAnnotatedMethods(sup, methods);
       
   526         Class<?>[] intfs = c.getInterfaces();
       
   527         for (Class<?> intf : intfs)
       
   528             getAnnotatedMethods(intf, methods);
       
   529         for (Method m : c.getMethods()) {
       
   530             // We are careful not to add m if it is inherited from a parent
       
   531             // class or interface, because duplicate methods lead to nasty
       
   532             // behaviour in eliminateCovariantMethods.
       
   533             if (m.getDeclaringClass() == c &&
       
   534                     (m.isAnnotationPresent(ManagedAttribute.class) ||
       
   535                      m.isAnnotationPresent(ManagedOperation.class)))
       
   536                 methods.add(m);
       
   537         }
       
   538     }
       
   539 
   463     static MBeanNotificationInfo[] findNotifications(Object moi) {
   540     static MBeanNotificationInfo[] findNotifications(Object moi) {
   464         if (!(moi instanceof NotificationBroadcaster))
   541         if (!(moi instanceof NotificationBroadcaster))
   465             return null;
   542             return null;
   466         MBeanNotificationInfo[] mbn =
   543         MBeanNotificationInfo[] mbn =
   467                 ((NotificationBroadcaster) moi).getNotificationInfo();
   544                 ((NotificationBroadcaster) moi).getNotificationInfo();
   468         if (mbn == null || mbn.length == 0)
   545         if (mbn == null || mbn.length == 0)
   469             return null;
   546             return findNotificationsFromAnnotations(moi.getClass());
   470         MBeanNotificationInfo[] result =
   547         MBeanNotificationInfo[] result =
   471                 new MBeanNotificationInfo[mbn.length];
   548                 new MBeanNotificationInfo[mbn.length];
   472         for (int i = 0; i < mbn.length; i++) {
   549         for (int i = 0; i < mbn.length; i++) {
   473             MBeanNotificationInfo ni = mbn[i];
   550             MBeanNotificationInfo ni = mbn[i];
   474             if (ni.getClass() != MBeanNotificationInfo.class)
   551             if (ni.getClass() != MBeanNotificationInfo.class)
   476             result[i] = ni;
   553             result[i] = ni;
   477         }
   554         }
   478         return result;
   555         return result;
   479     }
   556     }
   480 
   557 
       
   558     private static MBeanNotificationInfo[] findNotificationsFromAnnotations(
       
   559             Class<?> mbeanClass) {
       
   560         Class<?> c = getAnnotatedNotificationInfoClass(mbeanClass);
       
   561         if (c == null)
       
   562             return null;
       
   563         NotificationInfo ni = c.getAnnotation(NotificationInfo.class);
       
   564         NotificationInfos nis = c.getAnnotation(NotificationInfos.class);
       
   565         List<NotificationInfo> list = newList();
       
   566         if (ni != null)
       
   567             list.add(ni);
       
   568         if (nis != null)
       
   569             list.addAll(Arrays.asList(nis.value()));
       
   570         if (list.isEmpty())
       
   571             return null;
       
   572         List<MBeanNotificationInfo> mbnis = newList();
       
   573         for (NotificationInfo x : list) {
       
   574             // The Descriptor includes any fields explicitly specified by
       
   575             // x.descriptorFields(), plus any fields from the contained
       
   576             // @Description annotation.
       
   577             Descriptor d = new ImmutableDescriptor(x.descriptorFields());
       
   578             d = ImmutableDescriptor.union(
       
   579                     d, Introspector.descriptorForAnnotation(x.description()));
       
   580             MBeanNotificationInfo mbni = new MBeanNotificationInfo(
       
   581                     x.types(), x.notificationClass().getName(),
       
   582                     x.description().value(), d);
       
   583             mbnis.add(mbni);
       
   584         }
       
   585         return mbnis.toArray(new MBeanNotificationInfo[mbnis.size()]);
       
   586     }
       
   587 
       
   588     private static final Map<Class<?>, WeakReference<Class<?>>>
       
   589             annotatedNotificationInfoClasses = newWeakHashMap();
       
   590 
       
   591     private static Class<?> getAnnotatedNotificationInfoClass(Class<?> baseClass) {
       
   592         synchronized (annotatedNotificationInfoClasses) {
       
   593             WeakReference<Class<?>> wr =
       
   594                     annotatedNotificationInfoClasses.get(baseClass);
       
   595             if (wr != null)
       
   596                 return wr.get();
       
   597             Class<?> c = null;
       
   598             if (baseClass.isAnnotationPresent(NotificationInfo.class) ||
       
   599                     baseClass.isAnnotationPresent(NotificationInfos.class)) {
       
   600                 c = baseClass;
       
   601             } else {
       
   602                 Class<?>[] intfs = baseClass.getInterfaces();
       
   603                 for (Class<?> intf : intfs) {
       
   604                     Class<?> c1 = getAnnotatedNotificationInfoClass(intf);
       
   605                     if (c1 != null) {
       
   606                         if (c != null) {
       
   607                             throw new IllegalArgumentException(
       
   608                                     "Class " + baseClass.getName() + " inherits " +
       
   609                                     "@NotificationInfo(s) from both " +
       
   610                                     c.getName() + " and " + c1.getName());
       
   611                         }
       
   612                         c = c1;
       
   613                     }
       
   614                 }
       
   615             }
       
   616             // Record the result of the search.  If no @NotificationInfo(s)
       
   617             // were found, c is null, and we store a WeakReference(null).
       
   618             // This prevents us from having to search again and fail again.
       
   619             annotatedNotificationInfoClasses.put(baseClass,
       
   620                     new WeakReference<Class<?>>(c));
       
   621             return c;
       
   622         }
       
   623     }
       
   624 
   481     private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
   625     private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
   482         Constructor[] cons = c.getConstructors();
   626         Constructor[] cons = c.getConstructors();
   483         MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
   627         MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
   484         for (int i = 0; i < cons.length; i++) {
   628         for (int i = 0; i < cons.length; i++) {
   485             final String descr = "Public constructor of the MBean";
   629             String descr = "Public constructor of the MBean";
       
   630             Description d = cons[i].getAnnotation(Description.class);
       
   631             if (d != null)
       
   632                 descr = d.value();
   486             mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
   633             mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
   487         }
   634         }
   488         return mbc;
   635         return mbc;
   489     }
   636     }
   490 
   637