1 /*
2  * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.jmx.mbeanserver;
27 
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.lang.reflect.Type;
31 import java.util.WeakHashMap;
32 import javax.management.Descriptor;
33 import javax.management.ImmutableDescriptor;
34 import javax.management.IntrospectionException;
35 import javax.management.MBeanAttributeInfo;
36 import javax.management.MBeanException;
37 import javax.management.MBeanOperationInfo;
38 import javax.management.NotCompliantMBeanException;
39 import javax.management.NotificationBroadcaster;
40 import javax.management.NotificationBroadcasterSupport;
41 import sun.reflect.misc.MethodUtil;
42 
43 /**
44  * @since 1.6
45  */
46 class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
47     private static final StandardMBeanIntrospector instance =
48         new StandardMBeanIntrospector();
49 
getInstance()50     static StandardMBeanIntrospector getInstance() {
51         return instance;
52     }
53 
54     @Override
getPerInterfaceMap()55     PerInterfaceMap<Method> getPerInterfaceMap() {
56         return perInterfaceMap;
57     }
58 
59     @Override
getMBeanInfoMap()60     MBeanInfoMap getMBeanInfoMap() {
61         return mbeanInfoMap;
62     }
63 
64     @Override
getAnalyzer(Class<?> mbeanInterface)65     MBeanAnalyzer<Method> getAnalyzer(Class<?> mbeanInterface)
66             throws NotCompliantMBeanException {
67         return MBeanAnalyzer.analyzer(mbeanInterface, this);
68     }
69 
70     @Override
isMXBean()71     boolean isMXBean() {
72         return false;
73     }
74 
75     @Override
mFrom(Method m)76     Method mFrom(Method m) {
77         return m;
78     }
79 
80     @Override
getName(Method m)81     String getName(Method m) {
82         return m.getName();
83     }
84 
85     @Override
getGenericReturnType(Method m)86     Type getGenericReturnType(Method m) {
87         return m.getGenericReturnType();
88     }
89 
90     @Override
getGenericParameterTypes(Method m)91     Type[] getGenericParameterTypes(Method m) {
92         return m.getGenericParameterTypes();
93     }
94 
95     @Override
getSignature(Method m)96     String[] getSignature(Method m) {
97         Class<?>[] params = m.getParameterTypes();
98         String[] sig = new String[params.length];
99         for (int i = 0; i < params.length; i++)
100             sig[i] = params[i].getName();
101         return sig;
102     }
103 
104     @Override
checkMethod(Method m)105     void checkMethod(Method m) {
106     }
107 
108     @Override
invokeM2(Method m, Object target, Object[] args, Object cookie)109     Object invokeM2(Method m, Object target, Object[] args, Object cookie)
110             throws InvocationTargetException, IllegalAccessException,
111                    MBeanException {
112         return MethodUtil.invoke(m, target, args);
113     }
114 
115     @Override
validParameter(Method m, Object value, int paramNo, Object cookie)116     boolean validParameter(Method m, Object value, int paramNo, Object cookie) {
117         return isValidParameter(m, value, paramNo);
118     }
119 
120     @Override
getMBeanAttributeInfo(String attributeName, Method getter, Method setter)121     MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
122             Method getter, Method setter) {
123 
124         final String description = "Attribute exposed for management";
125         try {
126             return new MBeanAttributeInfo(attributeName, description,
127                                           getter, setter);
128         } catch (IntrospectionException e) {
129             throw new RuntimeException(e); // should not happen
130         }
131     }
132 
133     @Override
getMBeanOperationInfo(String operationName, Method operation)134     MBeanOperationInfo getMBeanOperationInfo(String operationName,
135             Method operation) {
136         final String description = "Operation exposed for management";
137         return new MBeanOperationInfo(description, operation);
138     }
139 
140     @Override
getBasicMBeanDescriptor()141     Descriptor getBasicMBeanDescriptor() {
142         /* We don't bother saying mxbean=false, and we can't know whether
143            the info is immutable until we know whether the MBean class
144            (not interface) is a NotificationBroadcaster. */
145         return ImmutableDescriptor.EMPTY_DESCRIPTOR;
146     }
147 
148     @Override
getMBeanDescriptor(Class<?> resourceClass)149     Descriptor getMBeanDescriptor(Class<?> resourceClass) {
150         boolean immutable = isDefinitelyImmutableInfo(resourceClass);
151         return new ImmutableDescriptor("mxbean=false",
152                                        "immutableInfo=" + immutable);
153     }
154 
155     /* Return true if and only if we can be sure that the given MBean implementation
156      * class has immutable MBeanInfo.  A Standard MBean that is a
157      * NotificationBroadcaster is allowed to return different values at
158      * different times from its getNotificationInfo() method, which is when
159      * we might not know if it is immutable.  But if it is a subclass of
160      * NotificationBroadcasterSupport and does not override
161      * getNotificationInfo(), then we know it won't change.
162      */
isDefinitelyImmutableInfo(Class<?> implClass)163     static boolean isDefinitelyImmutableInfo(Class<?> implClass) {
164         if (!NotificationBroadcaster.class.isAssignableFrom(implClass))
165             return true;
166         synchronized (definitelyImmutable) {
167             Boolean immutable = definitelyImmutable.get(implClass);
168             if (immutable == null) {
169                 final Class<NotificationBroadcasterSupport> nbs =
170                         NotificationBroadcasterSupport.class;
171                 if (nbs.isAssignableFrom(implClass)) {
172                     try {
173                         Method m = implClass.getMethod("getNotificationInfo");
174                         immutable = (m.getDeclaringClass() == nbs);
175                     } catch (Exception e) {
176                         // Too bad, we'll say no for now.
177                         return false;
178                     }
179                 } else
180                     immutable = false;
181                 definitelyImmutable.put(implClass, immutable);
182             }
183             return immutable;
184         }
185     }
186     private static final WeakHashMap<Class<?>, Boolean> definitelyImmutable =
187             new WeakHashMap<Class<?>, Boolean>();
188 
189     private static final PerInterfaceMap<Method>
190         perInterfaceMap = new PerInterfaceMap<Method>();
191 
192     private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
193 }
194