Path: blob/master/src/java.management/share/classes/com/sun/jmx/mbeanserver/PerInterface.java
41161 views
/*1* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.jmx.mbeanserver;2627import java.security.AccessController;28import java.util.Arrays;29import java.util.Collections;30import java.util.List;31import java.util.Map;32import javax.management.AttributeNotFoundException;33import javax.management.InvalidAttributeValueException;34import javax.management.MBeanException;35import javax.management.MBeanInfo;36import javax.management.ReflectionException;3738import static com.sun.jmx.mbeanserver.Util.*;3940/**41* Per-MBean-interface behavior. A single instance of this class can be shared42* by all MBeans of the same kind (Standard MBean or MXBean) that have the same43* MBean interface.44*45* @since 1.646*/47final class PerInterface<M> {48PerInterface(Class<?> mbeanInterface, MBeanIntrospector<M> introspector,49MBeanAnalyzer<M> analyzer, MBeanInfo mbeanInfo) {50this.mbeanInterface = mbeanInterface;51this.introspector = introspector;52this.mbeanInfo = mbeanInfo;53analyzer.visit(new InitMaps());54}5556Class<?> getMBeanInterface() {57return mbeanInterface;58}5960MBeanInfo getMBeanInfo() {61return mbeanInfo;62}6364boolean isMXBean() {65return introspector.isMXBean();66}6768Object getAttribute(Object resource, String attribute, Object cookie)69throws AttributeNotFoundException,70MBeanException,71ReflectionException {7273final M cm = getters.get(attribute);74if (cm == null) {75final String msg;76if (setters.containsKey(attribute))77msg = "Write-only attribute: " + attribute;78else79msg = "No such attribute: " + attribute;80throw new AttributeNotFoundException(msg);81}82return introspector.invokeM(cm, resource, (Object[]) null, cookie);83}8485void setAttribute(Object resource, String attribute, Object value,86Object cookie)87throws AttributeNotFoundException,88InvalidAttributeValueException,89MBeanException,90ReflectionException {9192final M cm = setters.get(attribute);93if (cm == null) {94final String msg;95if (getters.containsKey(attribute))96msg = "Read-only attribute: " + attribute;97else98msg = "No such attribute: " + attribute;99throw new AttributeNotFoundException(msg);100}101introspector.invokeSetter(attribute, cm, resource, value, cookie);102}103104Object invoke(Object resource, String operation, Object[] params,105String[] signature, Object cookie)106throws MBeanException, ReflectionException {107108final List<MethodAndSig> list = ops.get(operation);109if (list == null) {110final String msg = "No such operation: " + operation;111return noSuchMethod(msg, resource, operation, params, signature,112cookie);113}114if (signature == null)115signature = new String[0];116MethodAndSig found = null;117for (MethodAndSig mas : list) {118if (Arrays.equals(mas.signature, signature)) {119found = mas;120break;121}122}123if (found == null) {124final String badSig = sigString(signature);125final String msg;126if (list.size() == 1) { // helpful exception message127msg = "Signature mismatch for operation " + operation +128": " + badSig + " should be " +129sigString(list.get(0).signature);130} else {131msg = "Operation " + operation + " exists but not with " +132"this signature: " + badSig;133}134return noSuchMethod(msg, resource, operation, params, signature,135cookie);136}137return introspector.invokeM(found.method, resource, params, cookie);138}139140/*141* This method is called when invoke doesn't find the named method.142* Before throwing an exception, we check to see whether the143* jmx.invoke.getters property is set, and if so whether the method144* being invoked might be a getter or a setter. If so we invoke it145* and return the result. This is for compatibility146* with code based on JMX RI 1.0 or 1.1 which allowed invoking getters147* and setters. It is *not* recommended that new code use this feature.148*149* Since this method is either going to throw an exception or use150* functionality that is strongly discouraged, we consider that its151* performance is not very important.152*153* A simpler way to implement the functionality would be to add the getters154* and setters to the operations map when jmx.invoke.getters is set.155* However, that means that the property is consulted when an MBean156* interface is being introspected and not thereafter. Previously,157* the property was consulted on every invocation. So this simpler158* implementation could potentially break code that sets and unsets159* the property at different times.160*/161@SuppressWarnings("removal")162private Object noSuchMethod(String msg, Object resource, String operation,163Object[] params, String[] signature,164Object cookie)165throws MBeanException, ReflectionException {166167// Construct the exception that we will probably throw168final NoSuchMethodException nsme =169new NoSuchMethodException(operation + sigString(signature));170final ReflectionException exception =171new ReflectionException(nsme, msg);172173if (introspector.isMXBean())174throw exception; // No compatibility requirement here175176// Is the compatibility property set?177GetPropertyAction act = new GetPropertyAction("jmx.invoke.getters");178String invokeGettersS;179try {180invokeGettersS = AccessController.doPrivileged(act);181} catch (Exception e) {182// We don't expect an exception here but if we get one then183// we'll simply assume that the property is not set.184invokeGettersS = null;185}186if (invokeGettersS == null)187throw exception;188189int rest = 0;190Map<String, M> methods = null;191if (signature == null || signature.length == 0) {192if (operation.startsWith("get"))193rest = 3;194else if (operation.startsWith("is"))195rest = 2;196if (rest != 0)197methods = getters;198} else if (signature.length == 1 &&199operation.startsWith("set")) {200rest = 3;201methods = setters;202}203204if (rest != 0) {205String attrName = operation.substring(rest);206M method = methods.get(attrName);207if (method != null && introspector.getName(method).equals(operation)) {208String[] msig = introspector.getSignature(method);209if ((signature == null && msig.length == 0) ||210Arrays.equals(signature, msig)) {211return introspector.invokeM(method, resource, params, cookie);212}213}214}215216throw exception;217}218219private String sigString(String[] signature) {220StringBuilder b = new StringBuilder("(");221if (signature != null) {222for (String s : signature) {223if (b.length() > 1)224b.append(", ");225b.append(s);226}227}228return b.append(")").toString();229}230231/**232* Visitor that sets up the method maps (operations, getters, setters).233*/234private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M> {235public void visitAttribute(String attributeName,236M getter,237M setter) {238if (getter != null) {239introspector.checkMethod(getter);240final Object old = getters.put(attributeName, getter);241assert(old == null);242}243if (setter != null) {244introspector.checkMethod(setter);245final Object old = setters.put(attributeName, setter);246assert(old == null);247}248}249250public void visitOperation(String operationName,251M operation) {252introspector.checkMethod(operation);253final String[] sig = introspector.getSignature(operation);254final MethodAndSig mas = new MethodAndSig();255mas.method = operation;256mas.signature = sig;257List<MethodAndSig> list = ops.get(operationName);258if (list == null)259list = Collections.singletonList(mas);260else {261if (list.size() == 1)262list = newList(list);263list.add(mas);264}265ops.put(operationName, list);266}267}268269private class MethodAndSig {270M method;271String[] signature;272}273274private final Class<?> mbeanInterface;275private final MBeanIntrospector<M> introspector;276private final MBeanInfo mbeanInfo;277private final Map<String, M> getters = newMap();278private final Map<String, M> setters = newMap();279private final Map<String, List<MethodAndSig>> ops = newMap();280}281282283