001: package dalma.container;
002:
003: import javax.management.JMException;
004: import javax.management.MBeanRegistration;
005: import javax.management.MBeanServer;
006: import javax.management.ObjectName;
007: import javax.management.StandardMBean;
008: import javax.management.NotCompliantMBeanException;
009: import java.lang.ref.ReferenceQueue;
010: import java.lang.ref.WeakReference;
011: import java.lang.reflect.InvocationHandler;
012: import java.lang.reflect.InvocationTargetException;
013: import java.lang.reflect.Method;
014: import java.lang.reflect.Proxy;
015:
016: /**
017: * Proxy MBean that avoid strong reference to the real MBean object.
018: *
019: * @author Kohsuke Kawaguchi
020: */
021: final class MBeanProxy implements InvocationHandler, MBeanRegistration {
022:
023: /**
024: * Creates a proxy MBean and registers it to the server,
025: * overriding the existing mbean if necessary.
026: */
027: public static <T> void register(MBeanServer server,
028: ObjectName name, Class<T> mbeanInterface, T object)
029: throws JMException {
030: Object proxy = mbeanInterface.cast(Proxy.newProxyInstance(
031: mbeanInterface.getClassLoader(), new Class[] {
032: mbeanInterface, MBeanRegistration.class },
033: new MBeanProxy(object)));
034:
035: if (server.isRegistered(name)) {
036: try {
037: server.unregisterMBean(name);
038: } catch (JMException e) {
039: // if we fail to unregister, try to register ours anyway.
040: // maybe a GC kicked in in-between.
041: }
042: }
043:
044: // since the proxy class has random names like '$Proxy1',
045: // we need to use StandardMBean to designate a management interface
046: server.registerMBean(
047: new StandardMBeanEx(proxy, mbeanInterface), name);
048:
049: }
050:
051: private static class StandardMBeanEx extends StandardMBean
052: implements MBeanRegistration {
053: private MBeanRegistration mbr;
054:
055: public StandardMBeanEx(Object implementation,
056: Class mbeanInterface) throws NotCompliantMBeanException {
057: super (implementation, mbeanInterface);
058: this .mbr = (MBeanRegistration) implementation;
059: }
060:
061: // delegate to mbr
062: public ObjectName preRegister(MBeanServer server,
063: ObjectName name) throws Exception {
064: return mbr.preRegister(server, name);
065: }
066:
067: public void postRegister(Boolean registrationDone) {
068: mbr.postRegister(registrationDone);
069: }
070:
071: public void preDeregister() throws Exception {
072: mbr.preDeregister();
073: }
074:
075: public void postDeregister() {
076: mbr.postDeregister();
077: }
078: }
079:
080: /**
081: * The real MBean object.
082: */
083: private final ReferenceImpl real;
084: private MBeanServer server;
085: private ObjectName name;
086:
087: private MBeanProxy(Object realObject) {
088: this .real = new ReferenceImpl(realObject);
089: }
090:
091: public Object invoke(Object proxy, Method method, Object[] args)
092: throws Throwable {
093: Object o = real.get();
094:
095: if (method.getDeclaringClass() == MBeanRegistration.class) {
096: o = this ;
097: }
098:
099: if (o == null) {
100: unregister();
101: throw new IllegalStateException(name + " no longer exists");
102: }
103:
104: try {
105: return method.invoke(o, args);
106: } catch (InvocationTargetException e) {
107: if (e.getCause() != null)
108: throw e.getCause();
109: else
110: throw e;
111: }
112: }
113:
114: private synchronized void unregister() {
115: try {
116: server.unregisterMBean(name);
117: } catch (JMException e) {
118: throw new Error(e); // is this even possible?
119: }
120: }
121:
122: public synchronized ObjectName preRegister(MBeanServer server,
123: ObjectName name) throws Exception {
124: this .server = server;
125: this .name = name;
126: return name;
127: }
128:
129: public void postRegister(Boolean registrationDone) {
130: // noop
131: }
132:
133: public void preDeregister() throws Exception {
134: // noop
135: }
136:
137: public synchronized void postDeregister() {
138: server = null;
139: name = null;
140: }
141:
142: private class ReferenceImpl extends WeakReference<Object> {
143: public ReferenceImpl(Object referent) {
144: super (referent, queue);
145: }
146:
147: public MBeanProxy getProxy() {
148: return MBeanProxy.this ;
149: }
150: }
151:
152: private static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
153:
154: static {
155: Runnable r = new Runnable() {
156: public void run() {
157: while (true) {
158: ReferenceImpl ref;
159: try {
160: ref = (ReferenceImpl) (WeakReference<Object>) queue
161: .remove();
162: } catch (InterruptedException e) {
163: return;
164: }
165: ref.getProxy().unregister();
166: }
167: }
168: };
169: Thread t = new Thread(r, "Dalma JMX bean clenaer");
170: t.setDaemon(true);
171: t.start();
172: }
173: }
|