0N/A/*
2362N/A * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.jmx.mbeanserver;
0N/A
0N/Aimport java.security.AccessController;
0N/Aimport java.util.Arrays;
0N/Aimport java.util.Collections;
0N/Aimport java.util.List;
0N/Aimport java.util.Map;
0N/Aimport javax.management.AttributeNotFoundException;
0N/Aimport javax.management.InvalidAttributeValueException;
0N/Aimport javax.management.MBeanException;
0N/Aimport javax.management.MBeanInfo;
0N/Aimport javax.management.ReflectionException;
0N/A
0N/Aimport static com.sun.jmx.mbeanserver.Util.*;
0N/A
0N/A/**
0N/A * Per-MBean-interface behavior. A single instance of this class can be shared
0N/A * by all MBeans of the same kind (Standard MBean or MXBean) that have the same
0N/A * MBean interface.
0N/A *
0N/A * @since 1.6
0N/A */
0N/Afinal class PerInterface<M> {
0N/A PerInterface(Class<?> mbeanInterface, MBeanIntrospector<M> introspector,
0N/A MBeanAnalyzer<M> analyzer, MBeanInfo mbeanInfo) {
0N/A this.mbeanInterface = mbeanInterface;
0N/A this.introspector = introspector;
0N/A this.mbeanInfo = mbeanInfo;
0N/A analyzer.visit(new InitMaps());
0N/A }
0N/A
0N/A Class<?> getMBeanInterface() {
0N/A return mbeanInterface;
0N/A }
0N/A
0N/A MBeanInfo getMBeanInfo() {
0N/A return mbeanInfo;
0N/A }
0N/A
0N/A boolean isMXBean() {
0N/A return introspector.isMXBean();
0N/A }
0N/A
0N/A Object getAttribute(Object resource, String attribute, Object cookie)
0N/A throws AttributeNotFoundException,
0N/A MBeanException,
0N/A ReflectionException {
0N/A
0N/A final M cm = getters.get(attribute);
0N/A if (cm == null) {
0N/A final String msg;
0N/A if (setters.containsKey(attribute))
0N/A msg = "Write-only attribute: " + attribute;
0N/A else
0N/A msg = "No such attribute: " + attribute;
0N/A throw new AttributeNotFoundException(msg);
0N/A }
0N/A return introspector.invokeM(cm, resource, (Object[]) null, cookie);
0N/A }
0N/A
0N/A void setAttribute(Object resource, String attribute, Object value,
0N/A Object cookie)
0N/A throws AttributeNotFoundException,
0N/A InvalidAttributeValueException,
0N/A MBeanException,
0N/A ReflectionException {
0N/A
0N/A final M cm = setters.get(attribute);
0N/A if (cm == null) {
0N/A final String msg;
0N/A if (getters.containsKey(attribute))
0N/A msg = "Read-only attribute: " + attribute;
0N/A else
0N/A msg = "No such attribute: " + attribute;
0N/A throw new AttributeNotFoundException(msg);
0N/A }
0N/A introspector.invokeSetter(attribute, cm, resource, value, cookie);
0N/A }
0N/A
0N/A Object invoke(Object resource, String operation, Object[] params,
0N/A String[] signature, Object cookie)
0N/A throws MBeanException, ReflectionException {
0N/A
0N/A final List<MethodAndSig> list = ops.get(operation);
0N/A if (list == null) {
0N/A final String msg = "No such operation: " + operation;
0N/A return noSuchMethod(msg, resource, operation, params, signature,
0N/A cookie);
0N/A }
0N/A if (signature == null)
0N/A signature = new String[0];
0N/A MethodAndSig found = null;
0N/A for (MethodAndSig mas : list) {
0N/A if (Arrays.equals(mas.signature, signature)) {
0N/A found = mas;
0N/A break;
0N/A }
0N/A }
0N/A if (found == null) {
0N/A final String badSig = sigString(signature);
0N/A final String msg;
0N/A if (list.size() == 1) { // helpful exception message
0N/A msg = "Signature mismatch for operation " + operation +
0N/A ": " + badSig + " should be " +
0N/A sigString(list.get(0).signature);
0N/A } else {
0N/A msg = "Operation " + operation + " exists but not with " +
0N/A "this signature: " + badSig;
0N/A }
0N/A return noSuchMethod(msg, resource, operation, params, signature,
0N/A cookie);
0N/A }
0N/A return introspector.invokeM(found.method, resource, params, cookie);
0N/A }
0N/A
0N/A /*
0N/A * This method is called when invoke doesn't find the named method.
0N/A * Before throwing an exception, we check to see whether the
0N/A * jmx.invoke.getters property is set, and if so whether the method
0N/A * being invoked might be a getter or a setter. If so we invoke it
0N/A * and return the result. This is for compatibility
0N/A * with code based on JMX RI 1.0 or 1.1 which allowed invoking getters
0N/A * and setters. It is *not* recommended that new code use this feature.
0N/A *
0N/A * Since this method is either going to throw an exception or use
0N/A * functionality that is strongly discouraged, we consider that its
0N/A * performance is not very important.
0N/A *
0N/A * A simpler way to implement the functionality would be to add the getters
0N/A * and setters to the operations map when jmx.invoke.getters is set.
0N/A * However, that means that the property is consulted when an MBean
0N/A * interface is being introspected and not thereafter. Previously,
0N/A * the property was consulted on every invocation. So this simpler
0N/A * implementation could potentially break code that sets and unsets
0N/A * the property at different times.
0N/A */
0N/A private Object noSuchMethod(String msg, Object resource, String operation,
0N/A Object[] params, String[] signature,
0N/A Object cookie)
0N/A throws MBeanException, ReflectionException {
0N/A
0N/A // Construct the exception that we will probably throw
0N/A final NoSuchMethodException nsme =
0N/A new NoSuchMethodException(operation + sigString(signature));
0N/A final ReflectionException exception =
0N/A new ReflectionException(nsme, msg);
0N/A
0N/A if (introspector.isMXBean())
0N/A throw exception; // No compatibility requirement here
0N/A
0N/A // Is the compatibility property set?
0N/A GetPropertyAction act = new GetPropertyAction("jmx.invoke.getters");
0N/A String invokeGettersS;
0N/A try {
0N/A invokeGettersS = AccessController.doPrivileged(act);
0N/A } catch (Exception e) {
0N/A // We don't expect an exception here but if we get one then
0N/A // we'll simply assume that the property is not set.
0N/A invokeGettersS = null;
0N/A }
0N/A if (invokeGettersS == null)
0N/A throw exception;
0N/A
0N/A int rest = 0;
0N/A Map<String, M> methods = null;
0N/A if (signature == null || signature.length == 0) {
0N/A if (operation.startsWith("get"))
0N/A rest = 3;
0N/A else if (operation.startsWith("is"))
0N/A rest = 2;
0N/A if (rest != 0)
0N/A methods = getters;
0N/A } else if (signature.length == 1 &&
0N/A operation.startsWith("set")) {
0N/A rest = 3;
0N/A methods = setters;
0N/A }
0N/A
0N/A if (rest != 0) {
0N/A String attrName = operation.substring(rest);
0N/A M method = methods.get(attrName);
0N/A if (method != null && introspector.getName(method).equals(operation)) {
0N/A String[] msig = introspector.getSignature(method);
0N/A if ((signature == null && msig.length == 0) ||
0N/A Arrays.equals(signature, msig)) {
0N/A return introspector.invokeM(method, resource, params, cookie);
0N/A }
0N/A }
0N/A }
0N/A
0N/A throw exception;
0N/A }
0N/A
0N/A private String sigString(String[] signature) {
0N/A StringBuilder b = new StringBuilder("(");
0N/A if (signature != null) {
0N/A for (String s : signature) {
0N/A if (b.length() > 1)
0N/A b.append(", ");
0N/A b.append(s);
0N/A }
0N/A }
0N/A return b.append(")").toString();
0N/A }
0N/A
0N/A /**
0N/A * Visitor that sets up the method maps (operations, getters, setters).
0N/A */
1790N/A private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M> {
0N/A public void visitAttribute(String attributeName,
0N/A M getter,
0N/A M setter) {
0N/A if (getter != null) {
0N/A introspector.checkMethod(getter);
0N/A final Object old = getters.put(attributeName, getter);
0N/A assert(old == null);
0N/A }
0N/A if (setter != null) {
0N/A introspector.checkMethod(setter);
0N/A final Object old = setters.put(attributeName, setter);
0N/A assert(old == null);
0N/A }
0N/A }
0N/A
0N/A public void visitOperation(String operationName,
0N/A M operation) {
0N/A introspector.checkMethod(operation);
0N/A final String[] sig = introspector.getSignature(operation);
0N/A final MethodAndSig mas = new MethodAndSig();
0N/A mas.method = operation;
0N/A mas.signature = sig;
0N/A List<MethodAndSig> list = ops.get(operationName);
0N/A if (list == null)
0N/A list = Collections.singletonList(mas);
0N/A else {
0N/A if (list.size() == 1)
0N/A list = newList(list);
0N/A list.add(mas);
0N/A }
0N/A ops.put(operationName, list);
0N/A }
0N/A }
0N/A
0N/A private class MethodAndSig {
0N/A M method;
0N/A String[] signature;
0N/A }
0N/A
0N/A private final Class<?> mbeanInterface;
0N/A private final MBeanIntrospector<M> introspector;
0N/A private final MBeanInfo mbeanInfo;
0N/A private final Map<String, M> getters = newMap();
0N/A private final Map<String, M> setters = newMap();
0N/A private final Map<String, List<MethodAndSig>> ops = newMap();
0N/A}