6745832: jmx namespaces: Some refactoring/commenting would improve code readability.
Reviewed-by: emcmanus
/*
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import java.lang.reflect.Method;
import java.util.Map;
import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.openmbean.MXBeanMappingFactory;
/**
<p>Helper class for an {@link InvocationHandler} that forwards methods from an
MXBean interface to a named
MXBean in an MBean Server and handles translation between the
arbitrary Java types in the interface and the Open Types used
by the MXBean.</p>
@since 1.6
*/
public class MXBeanProxy {
public MXBeanProxy(Class<?> mxbeanInterface, MXBeanMappingFactory factory) {
if (mxbeanInterface == null)
throw new IllegalArgumentException("Null parameter");
final MBeanAnalyzer<ConvertingMethod> analyzer;
try {
analyzer =
MXBeanIntrospector.getInstance(factory).getAnalyzer(mxbeanInterface);
} catch (NotCompliantMBeanException e) {
throw new IllegalArgumentException(e);
}
analyzer.visit(new Visitor());
}
private class Visitor
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod, RuntimeException> {
public void visitAttribute(String attributeName,
ConvertingMethod getter,
ConvertingMethod setter) {
if (getter != null) {
getter.checkCallToOpen();
Method getterMethod = getter.getMethod();
handlerMap.put(getterMethod,
new GetHandler(attributeName, getter));
}
if (setter != null) {
// return type is void, no need for checkCallToOpen
Method setterMethod = setter.getMethod();
handlerMap.put(setterMethod,
new SetHandler(attributeName, setter));
}
}
public void visitOperation(String operationName,
ConvertingMethod operation) {
operation.checkCallToOpen();
Method operationMethod = operation.getMethod();
String[] sig = operation.getOpenSignature();
handlerMap.put(operationMethod,
new InvokeHandler(operationName, sig, operation));
}
}
private static abstract class Handler {
Handler(String name, ConvertingMethod cm) {
this.name = name;
this.convertingMethod = cm;
}
String getName() {
return name;
}
ConvertingMethod getConvertingMethod() {
return convertingMethod;
}
abstract Object invoke(MBeanServerConnection mbsc,
ObjectName name, Object[] args) throws Exception;
private final String name;
private final ConvertingMethod convertingMethod;
}
private static class GetHandler extends Handler {
GetHandler(String attributeName, ConvertingMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
assert(args == null || args.length == 0);
return mbsc.getAttribute(name, getName());
}
}
private static class SetHandler extends Handler {
SetHandler(String attributeName, ConvertingMethod cm) {
super(attributeName, cm);
}
@Override
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
assert(args.length == 1);
Attribute attr = new Attribute(getName(), args[0]);
mbsc.setAttribute(name, attr);
return null;
}
}
private static class InvokeHandler extends Handler {
InvokeHandler(String operationName, String[] signature,
ConvertingMethod cm) {
super(operationName, cm);
this.signature = signature;
}
Object invoke(MBeanServerConnection mbsc, ObjectName name, Object[] args)
throws Exception {
return mbsc.invoke(name, getName(), args, signature);
}
private final String[] signature;
}
public Object invoke(MBeanServerConnection mbsc, ObjectName name,
Method method, Object[] args)
throws Throwable {
Handler handler = handlerMap.get(method);
ConvertingMethod cm = handler.getConvertingMethod();
String prefix = extractPrefix(name);
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc, prefix);
MXBeanLookup oldLookup = MXBeanLookup.getLookup();
try {
MXBeanLookup.setLookup(lookup);
Object[] openArgs = cm.toOpenParameters(lookup, args);
Object result = handler.invoke(mbsc, name, openArgs);
return cm.fromOpenReturnValue(lookup, result);
} finally {
MXBeanLookup.setLookup(oldLookup);
}
}
private static String extractPrefix(ObjectName name)
throws MalformedObjectNameException {
String domain = name.getDomain();
int slashslash = domain.lastIndexOf("//");
if (slashslash > 0 && domain.charAt(slashslash - 1) == '/')
slashslash--;
if (slashslash >= 0)
return domain.substring(0, slashslash + 2);
else
return null;
}
private final Map<Method, Handler> handlerMap = newMap();
}