0N/A/*
2362N/A * Copyright (c) 2005, 2008, 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 static com.sun.jmx.mbeanserver.Util.*;
0N/Aimport java.util.Map;
0N/Aimport java.lang.ref.WeakReference;
0N/Aimport java.lang.reflect.InvocationHandler;
0N/Aimport java.lang.reflect.Proxy;
353N/Aimport java.security.AccessController;
353N/Aimport javax.management.InstanceAlreadyExistsException;
0N/Aimport javax.management.JMX;
0N/Aimport javax.management.MBeanServerConnection;
0N/Aimport javax.management.MBeanServerInvocationHandler;
0N/Aimport javax.management.ObjectName;
353N/Aimport javax.management.openmbean.OpenDataException;
0N/A
0N/A/**
0N/A * @since 1.6
0N/A */
0N/A
0N/A/*
0N/A * This class handles the mapping between MXBean references and
0N/A * ObjectNames. Consider an MXBean interface like this:
0N/A *
0N/A * public interface ModuleMXBean {
0N/A * ProductMXBean getProduct();
0N/A * void setProduct(ProductMXBean product);
0N/A * }
0N/A *
0N/A * This defines an attribute called "Product" whose originalType will
0N/A * be ProductMXBean and whose openType will be ObjectName. The
0N/A * mapping happens as follows.
0N/A *
0N/A * When the MXBean's getProduct method is called, it is supposed to
0N/A * return a reference to another MXBean, or a proxy for another
0N/A * MXBean. The MXBean layer has to convert this into an ObjectName.
0N/A * If it's a reference to another MXBean, it needs to be able to look
0N/A * up the name under which that MXBean has been registered in this
0N/A * MBeanServer; this is the purpose of the mxbeanToObjectName map. If
0N/A * it's a proxy, it can check that the MBeanServer matches and if so
0N/A * extract the ObjectName from the proxy.
0N/A *
0N/A * When the setProduct method is called on a proxy for this MXBean,
0N/A * the argument can be either an MXBean reference (only really logical
0N/A * if the proxy has a local MBeanServer) or another proxy. So the
0N/A * mapping logic is the same as for getProduct on the MXBean.
0N/A *
0N/A * When the MXBean's setProduct method is called, it needs to convert
0N/A * the ObjectName into an object implementing the ProductMXBean
0N/A * interface. We could have a lookup table that reverses
0N/A * mxbeanToObjectName, but this could violate the general JMX property
0N/A * that you cannot obtain a reference to an MBean object. So we
0N/A * always use a proxy for this. However we do have an
0N/A * objectNameToProxy map that allows us to reuse proxy instances.
0N/A *
0N/A * When the getProduct method is called on a proxy for this MXBean, it
0N/A * must convert the returned ObjectName into an instance of
0N/A * ProductMXBean. Again it can do this by making a proxy.
0N/A *
0N/A * From the above, it is clear that the logic for getX on an MXBean is
0N/A * the same as for setX on a proxy, and vice versa.
0N/A */
1790N/Apublic class MXBeanLookup {
0N/A private MXBeanLookup(MBeanServerConnection mbsc) {
0N/A this.mbsc = mbsc;
0N/A }
0N/A
1790N/A static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
1790N/A synchronized (mbscToLookup) {
1790N/A WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
1790N/A MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
1790N/A if (lookup == null) {
1790N/A lookup = new MXBeanLookup(mbsc);
1790N/A mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
0N/A }
1790N/A return lookup;
0N/A }
0N/A }
0N/A
1790N/A synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
1790N/A WeakReference<Object> wr = objectNameToProxy.get(name);
1790N/A if (wr != null) {
1790N/A Object proxy = wr.get();
1790N/A if (type.isInstance(proxy))
1790N/A return type.cast(proxy);
1790N/A }
1790N/A T proxy = JMX.newMXBeanProxy(mbsc, name, type);
1790N/A objectNameToProxy.put(name, new WeakReference<Object>(proxy));
1790N/A return proxy;
1790N/A }
1790N/A
1790N/A synchronized ObjectName mxbeanToObjectName(Object mxbean)
1790N/A throws OpenDataException {
1790N/A String wrong;
1790N/A if (mxbean instanceof Proxy) {
1790N/A InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
1790N/A if (ih instanceof MBeanServerInvocationHandler) {
1790N/A MBeanServerInvocationHandler mbsih =
1790N/A (MBeanServerInvocationHandler) ih;
1790N/A if (mbsih.getMBeanServerConnection().equals(mbsc))
1790N/A return mbsih.getObjectName();
1790N/A else
1790N/A wrong = "proxy for a different MBeanServer";
1790N/A } else
1790N/A wrong = "not a JMX proxy";
1790N/A } else {
1790N/A ObjectName name = mxbeanToObjectName.get(mxbean);
1790N/A if (name != null)
1790N/A return name;
1790N/A wrong = "not an MXBean registered in this MBeanServer";
0N/A }
1790N/A String s = (mxbean == null) ?
1790N/A "null" : "object of type " + mxbean.getClass().getName();
1790N/A throw new OpenDataException(
1790N/A "Could not convert " + s + " to an ObjectName: " + wrong);
1790N/A // Message will be strange if mxbean is null but it is not
1790N/A // supposed to be.
1790N/A }
1790N/A
1790N/A synchronized void addReference(ObjectName name, Object mxbean)
1790N/A throws InstanceAlreadyExistsException {
1790N/A ObjectName existing = mxbeanToObjectName.get(mxbean);
1790N/A if (existing != null) {
1790N/A String multiname = AccessController.doPrivileged(
1790N/A new GetPropertyAction("jmx.mxbean.multiname"));
1790N/A if (!"true".equalsIgnoreCase(multiname)) {
1790N/A throw new InstanceAlreadyExistsException(
1790N/A "MXBean already registered with name " + existing);
1790N/A }
1790N/A }
1790N/A mxbeanToObjectName.put(mxbean, name);
1790N/A }
1790N/A
1790N/A synchronized boolean removeReference(ObjectName name, Object mxbean) {
1790N/A if (name.equals(mxbeanToObjectName.get(mxbean))) {
1790N/A mxbeanToObjectName.remove(mxbean);
1790N/A return true;
1790N/A } else
1790N/A return false;
1790N/A /* removeReference can be called when the above condition fails,
1790N/A * notably if you try to register the same MXBean twice.
1790N/A */
353N/A }
353N/A
353N/A static MXBeanLookup getLookup() {
353N/A return currentLookup.get();
0N/A }
0N/A
353N/A static void setLookup(MXBeanLookup lookup) {
353N/A currentLookup.set(lookup);
0N/A }
0N/A
353N/A private static final ThreadLocal<MXBeanLookup> currentLookup =
353N/A new ThreadLocal<MXBeanLookup>();
353N/A
1790N/A private final MBeanServerConnection mbsc;
1790N/A private final WeakIdentityHashMap<Object, ObjectName>
1790N/A mxbeanToObjectName = WeakIdentityHashMap.make();
1790N/A private final Map<ObjectName, WeakReference<Object>>
1790N/A objectNameToProxy = newMap();
1790N/A private static final WeakIdentityHashMap<MBeanServerConnection,
1790N/A WeakReference<MXBeanLookup>>
1790N/A mbscToLookup = WeakIdentityHashMap.make();
0N/A}