Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/jmx/mbeanserver/PerInterface.java
38924 views
/*1* Copyright (c) 2005, 2006, 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*/161private Object noSuchMethod(String msg, Object resource, String operation,162Object[] params, String[] signature,163Object cookie)164throws MBeanException, ReflectionException {165166// Construct the exception that we will probably throw167final NoSuchMethodException nsme =168new NoSuchMethodException(operation + sigString(signature));169final ReflectionException exception =170new ReflectionException(nsme, msg);171172if (introspector.isMXBean())173throw exception; // No compatibility requirement here174175// Is the compatibility property set?176GetPropertyAction act = new GetPropertyAction("jmx.invoke.getters");177String invokeGettersS;178try {179invokeGettersS = AccessController.doPrivileged(act);180} catch (Exception e) {181// We don't expect an exception here but if we get one then182// we'll simply assume that the property is not set.183invokeGettersS = null;184}185if (invokeGettersS == null)186throw exception;187188int rest = 0;189Map<String, M> methods = null;190if (signature == null || signature.length == 0) {191if (operation.startsWith("get"))192rest = 3;193else if (operation.startsWith("is"))194rest = 2;195if (rest != 0)196methods = getters;197} else if (signature.length == 1 &&198operation.startsWith("set")) {199rest = 3;200methods = setters;201}202203if (rest != 0) {204String attrName = operation.substring(rest);205M method = methods.get(attrName);206if (method != null && introspector.getName(method).equals(operation)) {207String[] msig = introspector.getSignature(method);208if ((signature == null && msig.length == 0) ||209Arrays.equals(signature, msig)) {210return introspector.invokeM(method, resource, params, cookie);211}212}213}214215throw exception;216}217218private String sigString(String[] signature) {219StringBuilder b = new StringBuilder("(");220if (signature != null) {221for (String s : signature) {222if (b.length() > 1)223b.append(", ");224b.append(s);225}226}227return b.append(")").toString();228}229230/**231* Visitor that sets up the method maps (operations, getters, setters).232*/233private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M> {234public void visitAttribute(String attributeName,235M getter,236M setter) {237if (getter != null) {238introspector.checkMethod(getter);239final Object old = getters.put(attributeName, getter);240assert(old == null);241}242if (setter != null) {243introspector.checkMethod(setter);244final Object old = setters.put(attributeName, setter);245assert(old == null);246}247}248249public void visitOperation(String operationName,250M operation) {251introspector.checkMethod(operation);252final String[] sig = introspector.getSignature(operation);253final MethodAndSig mas = new MethodAndSig();254mas.method = operation;255mas.signature = sig;256List<MethodAndSig> list = ops.get(operationName);257if (list == null)258list = Collections.singletonList(mas);259else {260if (list.size() == 1)261list = newList(list);262list.add(mas);263}264ops.put(operationName, list);265}266}267268private class MethodAndSig {269M method;270String[] signature;271}272273private final Class<?> mbeanInterface;274private final MBeanIntrospector<M> introspector;275private final MBeanInfo mbeanInfo;276private final Map<String, M> getters = newMap();277private final Map<String, M> setters = newMap();278private final Map<String, List<MethodAndSig>> ops = newMap();279}280281282