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
26package com.sun.jmx.mbeanserver;
27
28import java.lang.reflect.InvocationTargetException;
29import java.lang.reflect.Method;
30import java.lang.reflect.Type;
31import java.util.WeakHashMap;
32import javax.management.Descriptor;
33import javax.management.ImmutableDescriptor;
34import javax.management.IntrospectionException;
35import javax.management.MBeanAttributeInfo;
36import javax.management.MBeanException;
37import javax.management.MBeanOperationInfo;
38import javax.management.NotCompliantMBeanException;
39import javax.management.NotificationBroadcaster;
40import javax.management.NotificationBroadcasterSupport;
41import sun.reflect.misc.MethodUtil;
42
43/**
44 * @since 1.6
45 */
46class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
47    private static final StandardMBeanIntrospector instance =
48        new StandardMBeanIntrospector();
49
50    static StandardMBeanIntrospector getInstance() {
51        return instance;
52    }
53
54    @Override
55    PerInterfaceMap<Method> getPerInterfaceMap() {
56        return perInterfaceMap;
57    }
58
59    @Override
60    MBeanInfoMap getMBeanInfoMap() {
61        return mbeanInfoMap;
62    }
63
64    @Override
65    MBeanAnalyzer<Method> getAnalyzer(Class<?> mbeanInterface)
66            throws NotCompliantMBeanException {
67        return MBeanAnalyzer.analyzer(mbeanInterface, this);
68    }
69
70    @Override
71    boolean isMXBean() {
72        return false;
73    }
74
75    @Override
76    Method mFrom(Method m) {
77        return m;
78    }
79
80    @Override
81    String getName(Method m) {
82        return m.getName();
83    }
84
85    @Override
86    Type getGenericReturnType(Method m) {
87        return m.getGenericReturnType();
88    }
89
90    @Override
91    Type[] getGenericParameterTypes(Method m) {
92        return m.getGenericParameterTypes();
93    }
94
95    @Override
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
105    void checkMethod(Method m) {
106    }
107
108    @Override
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
116    boolean validParameter(Method m, Object value, int paramNo, Object cookie) {
117        return isValidParameter(m, value, paramNo);
118    }
119
120    @Override
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
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
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
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     */
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