MXBeanLookup.java 7.6 KB
Newer Older
D
duke 已提交
1
/*
X
xdono 已提交
2
 * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
D
duke 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 * 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.util.Map;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
33 34
import java.security.AccessController;
import javax.management.InstanceAlreadyExistsException;
D
duke 已提交
35 36 37 38
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
39
import javax.management.openmbean.OpenDataException;
D
duke 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

/**
 * @since 1.6
 */

/*
 * This class handles the mapping between MXBean references and
 * ObjectNames.  Consider an MXBean interface like this:
 *
 * public interface ModuleMXBean {
 *     ProductMXBean getProduct();
 *     void setProduct(ProductMXBean product);
 * }
 *
 * This defines an attribute called "Product" whose originalType will
 * be ProductMXBean and whose openType will be ObjectName.  The
 * mapping happens as follows.
 *
 * When the MXBean's getProduct method is called, it is supposed to
 * return a reference to another MXBean, or a proxy for another
 * MXBean.  The MXBean layer has to convert this into an ObjectName.
 * If it's a reference to another MXBean, it needs to be able to look
 * up the name under which that MXBean has been registered in this
 * MBeanServer; this is the purpose of the mxbeanToObjectName map.  If
 * it's a proxy, it can check that the MBeanServer matches and if so
 * extract the ObjectName from the proxy.
 *
 * When the setProduct method is called on a proxy for this MXBean,
 * the argument can be either an MXBean reference (only really logical
 * if the proxy has a local MBeanServer) or another proxy.  So the
 * mapping logic is the same as for getProduct on the MXBean.
 *
 * When the MXBean's setProduct method is called, it needs to convert
 * the ObjectName into an object implementing the ProductMXBean
 * interface.  We could have a lookup table that reverses
 * mxbeanToObjectName, but this could violate the general JMX property
 * that you cannot obtain a reference to an MBean object.  So we
 * always use a proxy for this.  However we do have an
 * objectNameToProxy map that allows us to reuse proxy instances.
 *
 * When the getProduct method is called on a proxy for this MXBean, it
 * must convert the returned ObjectName into an instance of
 * ProductMXBean.  Again it can do this by making a proxy.
 *
 * From the above, it is clear that the logic for getX on an MXBean is
 * the same as for setX on a proxy, and vice versa.
 */
87
public class MXBeanLookup {
D
duke 已提交
88 89 90 91
    private MXBeanLookup(MBeanServerConnection mbsc) {
        this.mbsc = mbsc;
    }

92 93 94 95 96 97 98
    static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
        synchronized (mbscToLookup) {
            WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
            MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
            if (lookup == null) {
                lookup = new MXBeanLookup(mbsc);
                mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
99
            }
100
            return lookup;
101
        }
102
    }
103

104 105 106 107 108 109
    synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
        WeakReference<Object> wr = objectNameToProxy.get(name);
        if (wr != null) {
            Object proxy = wr.get();
            if (type.isInstance(proxy))
                return type.cast(proxy);
110
        }
111 112 113 114
        T proxy = JMX.newMXBeanProxy(mbsc, name, type);
        objectNameToProxy.put(name, new WeakReference<Object>(proxy));
        return proxy;
    }
115

116 117 118 119 120 121 122 123 124 125 126 127
    synchronized ObjectName mxbeanToObjectName(Object mxbean)
    throws OpenDataException {
        String wrong;
        if (mxbean instanceof Proxy) {
            InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
            if (ih instanceof MBeanServerInvocationHandler) {
                MBeanServerInvocationHandler mbsih =
                        (MBeanServerInvocationHandler) ih;
                if (mbsih.getMBeanServerConnection().equals(mbsc))
                    return mbsih.getObjectName();
                else
                    wrong = "proxy for a different MBeanServer";
128
            } else
129 130 131 132 133 134
                wrong = "not a JMX proxy";
        } else {
            ObjectName name = mxbeanToObjectName.get(mxbean);
            if (name != null)
                return name;
            wrong = "not an MXBean registered in this MBeanServer";
D
duke 已提交
135
        }
136 137 138 139 140 141
        String s = (mxbean == null) ?
            "null" : "object of type " + mxbean.getClass().getName();
        throw new OpenDataException(
                "Could not convert " + s + " to an ObjectName: " + wrong);
        // Message will be strange if mxbean is null but it is not
        // supposed to be.
D
duke 已提交
142 143
    }

144 145 146 147 148 149 150 151 152
    synchronized void addReference(ObjectName name, Object mxbean)
    throws InstanceAlreadyExistsException {
        ObjectName existing = mxbeanToObjectName.get(mxbean);
        if (existing != null) {
            String multiname = AccessController.doPrivileged(
                    new GetPropertyAction("jmx.mxbean.multiname"));
            if (!"true".equalsIgnoreCase(multiname)) {
                throw new InstanceAlreadyExistsException(
                        "MXBean already registered with name " + existing);
153 154
            }
        }
155
        mxbeanToObjectName.put(mxbean, name);
156 157
    }

158 159 160 161 162 163 164 165 166
    synchronized boolean removeReference(ObjectName name, Object mxbean) {
        if (name.equals(mxbeanToObjectName.get(mxbean))) {
            mxbeanToObjectName.remove(mxbean);
            return true;
        } else
            return false;
        /* removeReference can be called when the above condition fails,
         * notably if you try to register the same MXBean twice.
         */
167 168 169 170
    }

    static MXBeanLookup getLookup() {
        return currentLookup.get();
D
duke 已提交
171 172
    }

173 174
    static void setLookup(MXBeanLookup lookup) {
        currentLookup.set(lookup);
D
duke 已提交
175 176
    }

177 178 179
    private static final ThreadLocal<MXBeanLookup> currentLookup =
            new ThreadLocal<MXBeanLookup>();

180 181 182 183 184 185 186 187
    private final MBeanServerConnection mbsc;
    private final WeakIdentityHashMap<Object, ObjectName>
        mxbeanToObjectName = WeakIdentityHashMap.make();
    private final Map<ObjectName, WeakReference<Object>>
        objectNameToProxy = newMap();
    private static final WeakIdentityHashMap<MBeanServerConnection,
                                             WeakReference<MXBeanLookup>>
        mbscToLookup = WeakIdentityHashMap.make();
D
duke 已提交
188
}