Path: blob/master/src/java.management/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.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 static com.sun.jmx.mbeanserver.Util.*;28import java.util.Map;29import java.lang.ref.WeakReference;30import java.lang.reflect.InvocationHandler;31import java.lang.reflect.Proxy;32import java.security.AccessController;33import javax.management.InstanceAlreadyExistsException;34import javax.management.JMX;35import javax.management.MBeanServerConnection;36import javax.management.MBeanServerInvocationHandler;37import javax.management.ObjectName;38import javax.management.openmbean.OpenDataException;3940/**41* @since 1.642*/4344/*45* This class handles the mapping between MXBean references and46* ObjectNames. Consider an MXBean interface like this:47*48* public interface ModuleMXBean {49* ProductMXBean getProduct();50* void setProduct(ProductMXBean product);51* }52*53* This defines an attribute called "Product" whose originalType will54* be ProductMXBean and whose openType will be ObjectName. The55* mapping happens as follows.56*57* When the MXBean's getProduct method is called, it is supposed to58* return a reference to another MXBean, or a proxy for another59* MXBean. The MXBean layer has to convert this into an ObjectName.60* If it's a reference to another MXBean, it needs to be able to look61* up the name under which that MXBean has been registered in this62* MBeanServer; this is the purpose of the mxbeanToObjectName map. If63* it's a proxy, it can check that the MBeanServer matches and if so64* extract the ObjectName from the proxy.65*66* When the setProduct method is called on a proxy for this MXBean,67* the argument can be either an MXBean reference (only really logical68* if the proxy has a local MBeanServer) or another proxy. So the69* mapping logic is the same as for getProduct on the MXBean.70*71* When the MXBean's setProduct method is called, it needs to convert72* the ObjectName into an object implementing the ProductMXBean73* interface. We could have a lookup table that reverses74* mxbeanToObjectName, but this could violate the general JMX property75* that you cannot obtain a reference to an MBean object. So we76* always use a proxy for this. However we do have an77* objectNameToProxy map that allows us to reuse proxy instances.78*79* When the getProduct method is called on a proxy for this MXBean, it80* must convert the returned ObjectName into an instance of81* ProductMXBean. Again it can do this by making a proxy.82*83* From the above, it is clear that the logic for getX on an MXBean is84* the same as for setX on a proxy, and vice versa.85*/86public class MXBeanLookup {87private MXBeanLookup(MBeanServerConnection mbsc) {88this.mbsc = mbsc;89}9091static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {92synchronized (mbscToLookup) {93WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);94MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();95if (lookup == null) {96lookup = new MXBeanLookup(mbsc);97mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));98}99return lookup;100}101}102103synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {104WeakReference<Object> wr = objectNameToProxy.get(name);105if (wr != null) {106Object proxy = wr.get();107if (type.isInstance(proxy))108return type.cast(proxy);109}110T proxy = JMX.newMXBeanProxy(mbsc, name, type);111objectNameToProxy.put(name, new WeakReference<Object>(proxy));112return proxy;113}114115synchronized ObjectName mxbeanToObjectName(Object mxbean)116throws OpenDataException {117String wrong;118if (mxbean instanceof Proxy) {119InvocationHandler ih = Proxy.getInvocationHandler(mxbean);120if (ih instanceof MBeanServerInvocationHandler) {121MBeanServerInvocationHandler mbsih =122(MBeanServerInvocationHandler) ih;123if (mbsih.getMBeanServerConnection().equals(mbsc))124return mbsih.getObjectName();125else126wrong = "proxy for a different MBeanServer";127} else128wrong = "not a JMX proxy";129} else {130ObjectName name = mxbeanToObjectName.get(mxbean);131if (name != null)132return name;133wrong = "not an MXBean registered in this MBeanServer";134}135String s = (mxbean == null) ?136"null" : "object of type " + mxbean.getClass().getName();137throw new OpenDataException(138"Could not convert " + s + " to an ObjectName: " + wrong);139// Message will be strange if mxbean is null but it is not140// supposed to be.141}142143synchronized void addReference(ObjectName name, Object mxbean)144throws InstanceAlreadyExistsException {145ObjectName existing = mxbeanToObjectName.get(mxbean);146if (existing != null) {147@SuppressWarnings("removal")148String multiname = AccessController.doPrivileged(149new GetPropertyAction("jmx.mxbean.multiname"));150if (!"true".equalsIgnoreCase(multiname)) {151throw new InstanceAlreadyExistsException(152"MXBean already registered with name " + existing);153}154}155mxbeanToObjectName.put(mxbean, name);156}157158synchronized boolean removeReference(ObjectName name, Object mxbean) {159if (name.equals(mxbeanToObjectName.get(mxbean))) {160mxbeanToObjectName.remove(mxbean);161return true;162} else163return false;164/* removeReference can be called when the above condition fails,165* notably if you try to register the same MXBean twice.166*/167}168169static MXBeanLookup getLookup() {170return currentLookup.get();171}172173static void setLookup(MXBeanLookup lookup) {174currentLookup.set(lookup);175}176177private static final ThreadLocal<MXBeanLookup> currentLookup =178new ThreadLocal<MXBeanLookup>();179180private final MBeanServerConnection mbsc;181private final WeakIdentityHashMap<Object, ObjectName>182mxbeanToObjectName = WeakIdentityHashMap.make();183private final Map<ObjectName, WeakReference<Object>>184objectNameToProxy = newMap();185private static final WeakIdentityHashMap<MBeanServerConnection,186WeakReference<MXBeanLookup>>187mbscToLookup = WeakIdentityHashMap.make();188}189190191