blob: ef712eaafd881453289675f2dd4fc9599f97788d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.jmx.mbeanserver;
27
28import static com.sun.jmx.mbeanserver.Util.*;
29import java.util.Map;
30import java.lang.ref.WeakReference;
31import java.lang.reflect.InvocationHandler;
32import java.lang.reflect.Proxy;
33import javax.management.JMX;
34import javax.management.MBeanServerConnection;
35import javax.management.MBeanServerInvocationHandler;
36import javax.management.ObjectName;
37
38/**
39 * @since 1.6
40 */
41
42/*
43 * This class handles the mapping between MXBean references and
44 * ObjectNames. Consider an MXBean interface like this:
45 *
46 * public interface ModuleMXBean {
47 * ProductMXBean getProduct();
48 * void setProduct(ProductMXBean product);
49 * }
50 *
51 * This defines an attribute called "Product" whose originalType will
52 * be ProductMXBean and whose openType will be ObjectName. The
53 * mapping happens as follows.
54 *
55 * When the MXBean's getProduct method is called, it is supposed to
56 * return a reference to another MXBean, or a proxy for another
57 * MXBean. The MXBean layer has to convert this into an ObjectName.
58 * If it's a reference to another MXBean, it needs to be able to look
59 * up the name under which that MXBean has been registered in this
60 * MBeanServer; this is the purpose of the mxbeanToObjectName map. If
61 * it's a proxy, it can check that the MBeanServer matches and if so
62 * extract the ObjectName from the proxy.
63 *
64 * When the setProduct method is called on a proxy for this MXBean,
65 * the argument can be either an MXBean reference (only really logical
66 * if the proxy has a local MBeanServer) or another proxy. So the
67 * mapping logic is the same as for getProduct on the MXBean.
68 *
69 * When the MXBean's setProduct method is called, it needs to convert
70 * the ObjectName into an object implementing the ProductMXBean
71 * interface. We could have a lookup table that reverses
72 * mxbeanToObjectName, but this could violate the general JMX property
73 * that you cannot obtain a reference to an MBean object. So we
74 * always use a proxy for this. However we do have an
75 * objectNameToProxy map that allows us to reuse proxy instances.
76 *
77 * When the getProduct method is called on a proxy for this MXBean, it
78 * must convert the returned ObjectName into an instance of
79 * ProductMXBean. Again it can do this by making a proxy.
80 *
81 * From the above, it is clear that the logic for getX on an MXBean is
82 * the same as for setX on a proxy, and vice versa.
83 */
84public class MXBeanLookup {
85 private MXBeanLookup(MBeanServerConnection mbsc) {
86 this.mbsc = mbsc;
87 }
88
89 static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
90 synchronized (mbscToLookup) {
91 WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
92 MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
93 if (lookup == null) {
94 lookup = new MXBeanLookup(mbsc);
95 mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
96 }
97 return lookup;
98 }
99 }
100
101 synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
102 WeakReference<Object> wr = objectNameToProxy.get(name);
103 if (wr != null) {
104 Object proxy = wr.get();
105 if (type.isInstance(proxy))
106 return type.cast(proxy);
107 }
108 T proxy = JMX.newMXBeanProxy(mbsc, name, type);
109 objectNameToProxy.put(name, new WeakReference<Object>(proxy));
110 return proxy;
111 }
112
113 synchronized ObjectName mxbeanToObjectName(Object mxbean) {
114 if (mxbean instanceof Proxy) {
115 InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
116 if (ih instanceof MBeanServerInvocationHandler) {
117 MBeanServerInvocationHandler mbsih =
118 (MBeanServerInvocationHandler) ih;
119 if (mbsih.getMBeanServerConnection().equals(mbsc))
120 return mbsih.getObjectName();
121 }
122 return null;
123 } else
124 return mxbeanToObjectName.get(mxbean);
125 }
126
127 synchronized void addReference(ObjectName name, Object mxbean) {
128 mxbeanToObjectName.put(mxbean, name);
129 }
130
131 synchronized boolean removeReference(ObjectName name, Object mxbean) {
132 if (name.equals(mxbeanToObjectName.get(mxbean))) {
133 mxbeanToObjectName.remove(mxbean);
134 return true;
135 } else
136 return false;
137 /* removeReference can be called when the above condition fails,
138 * notably if you try to register the same MXBean twice.
139 */
140 }
141
142 private final MBeanServerConnection mbsc;
143 private final WeakIdentityHashMap<Object, ObjectName>
144 mxbeanToObjectName = WeakIdentityHashMap.make();
145 private final Map<ObjectName, WeakReference<Object>>
146 objectNameToProxy = newMap();
147 private static WeakIdentityHashMap<MBeanServerConnection,
148 WeakReference<MXBeanLookup>>
149 mbscToLookup = WeakIdentityHashMap.make();
150}