src/share/jaxws_classes/com/sun/org/glassfish/external/amx/MBeanListener.java

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
1 /*
2 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27 package com.sun.org.glassfish.external.amx;
28
29 import java.util.Set;
30 import javax.management.MBeanServer;
31 import javax.management.MBeanServerConnection;
32 import javax.management.MBeanServerNotification;
33 import javax.management.Notification;
34 import javax.management.NotificationListener;
35 import javax.management.ObjectName;
36 import java.util.concurrent.CountDownLatch;
37
38 import static com.sun.org.glassfish.external.amx.AMX.*;
39
40 /**
41 * Listens for registration of MBeans of various types.
42 * Intended usage is for subsystems to lazy-load only when the Parent
43 * MBean is registered.
44 */
45 @com.sun.org.glassfish.external.arc.Taxonomy(stability = com.sun.org.glassfish.external.arc.Stability.UNCOMMITTED)
46 public class MBeanListener<T extends MBeanListener.Callback> implements NotificationListener
47 {
48 private static void debug(final Object o) { System.out.println( "" + o ); }
49
50 /** listen for MBeans in a given domain of a given type[name]
51 OR an ObjectName (below) */
52 private final String mJMXDomain;
53 private final String mType;
54 private final String mName;
55
56 /** mType and mName should be null if mObjectName is non-null, and vice versa */
57 private final ObjectName mObjectName;
58
59 private final MBeanServerConnection mMBeanServer;
60
61 private final T mCallback;
62
63 public String toString()
64 {
65 return "MBeanListener: ObjectName=" + mObjectName + ", type=" + mType + ", name=" + mName;
66 }
67
68 public String getType()
69 {
70 return mType;
71 }
72
73 public String getName()
74 {
75 return mName;
76 }
77
78 public MBeanServerConnection getMBeanServer()
79 {
80 return mMBeanServer;
81 }
82
83 /** Callback interface. */
84 public interface Callback
85 {
86 public void mbeanRegistered(final ObjectName objectName, final MBeanListener listener);
87 public void mbeanUnregistered(final ObjectName objectName, final MBeanListener listener);
88 }
89
90 /**
91 Default callback implementation, can be subclassed if needed
92 Remembers only the last MBean that was seen.
93 */
94 public static class CallbackImpl implements MBeanListener.Callback
95 {
96 private volatile ObjectName mRegistered = null;
97 private volatile ObjectName mUnregistered = null;
98 private final boolean mStopAtFirst;
99
100 public CallbackImpl() {
101 this(true);
102 }
103
104 public CallbackImpl(final boolean stopAtFirst)
105 {
106 mStopAtFirst = stopAtFirst;
107 }
108
109 public ObjectName getRegistered() { return mRegistered; }
110 public ObjectName getUnregistered() { return mUnregistered; }
111
112 protected final CountDownLatch mLatch = new CountDownLatch(1);
113
114 /** Optional: wait for the CountDownLatch to fire
115 If used, the subclass should countDown() the latch when the
116 appropriate event happens
117 */
118 public void await()
119 {
120 try
121 {
122 mLatch.await(); // wait until BootAMXMBean is ready
123 }
124 catch (InterruptedException e)
125 {
126 throw new RuntimeException(e);
127 }
128 }
129
130 public void mbeanRegistered(final ObjectName objectName, final MBeanListener listener)
131 {
132 mRegistered = objectName;
133 if ( mStopAtFirst )
134 {
135 listener.stopListening();
136 }
137 }
138 public void mbeanUnregistered(final ObjectName objectName, final MBeanListener listener)
139 {
140 mUnregistered = objectName;
141 if ( mStopAtFirst )
142 {
143 listener.stopListening();
144 }
145 }
146 }
147
148 public T getCallback()
149 {
150 return mCallback;
151 }
152
153 /**
154 * Listener for a specific MBean.
155 * Caller must call {@link #start} to start listening.
156 * @param server
157 * @param objectName
158 * @param callback
159 */
160 public MBeanListener(
161 final MBeanServerConnection server,
162 final ObjectName objectName,
163 final T callback)
164 {
165 mMBeanServer = server;
166 mObjectName = objectName;
167 mJMXDomain = null;
168 mType = null;
169 mName = null;
170 mCallback = callback;
171 }
172
173 /**
174 * Listener for all MBeans of specified type, with or without a name.
175 * Caller must call {@link #start} to start listening.
176 * @param server
177 * @param type type of the MBean (as found in the ObjectName)
178 * @param callback
179 */
180 public MBeanListener(
181 final MBeanServerConnection server,
182 final String domain,
183 final String type,
184 final T callback)
185 {
186 this(server, domain, type, null, callback);
187 }
188
189 /**
190 * Listener for MBeans of specified type, with specified name (or any name
191 * if null is passed for the name).
192 * Caller must call {@link #start} to start listening.
193 * @param server
194 * @param type type of the MBean (as found in the ObjectName)
195 * @param name name of the MBean, or null if none
196 * @param callback
197 */
198 public MBeanListener(
199 final MBeanServerConnection server,
200 final String domain,
201 final String type,
202 final String name,
203 final T callback)
204 {
205 mMBeanServer = server;
206 mJMXDomain = domain;
207 mType = type;
208 mName = name;
209 mObjectName = null;
210 mCallback = callback;
211 }
212
213
214 private boolean isRegistered( final MBeanServerConnection conn, final ObjectName objectName )
215 {
216 try
217 {
218 return conn.isRegistered(objectName);
219 }
220 catch (final Exception e)
221 {
222 throw new RuntimeException(e);
223 }
224 }
225
226 /**
227 Start listening. If the required MBean(s) are already present, the callback
228 will be synchronously made before returning. It is also possible that the
229 callback could happen twice for the same MBean.
230 */
231 public void startListening()
232 {
233 // race condition: must listen *before* looking for existing MBeans
234 try
235 {
236 mMBeanServer.addNotificationListener( AMXUtil.getMBeanServerDelegateObjectName(), this, null, this);
237 }
238 catch (final Exception e)
239 {
240 throw new RuntimeException("Can't add NotificationListener", e);
241 }
242
243 if ( mObjectName != null )
244 {
245 if ( isRegistered(mMBeanServer, mObjectName) )
246 {
247 mCallback.mbeanRegistered(mObjectName, this);
248 }
249 }
250 else
251 {
252 // query for AMX MBeans of the requisite type
253 String props = TYPE_KEY + "=" + mType;
254 if (mName != null)
255 {
256 props = props + "," + NAME_KEY + mName;
257 }
258
259 final ObjectName pattern = AMXUtil.newObjectName(mJMXDomain + ":" +props);
260 try
261 {
262 final Set<ObjectName> matched = mMBeanServer.queryNames(pattern, null);
263 for (final ObjectName objectName : matched)
264 {
265 mCallback.mbeanRegistered(objectName, this);
266 }
267 }
268 catch( final Exception e )
269 {
270 throw new RuntimeException(e);
271 }
272 }
273 }
274
275
276 /** unregister the listener */
277 public void stopListening()
278 {
279 try
280 {
281 mMBeanServer.removeNotificationListener( AMXUtil.getMBeanServerDelegateObjectName(), this);
282 }
283 catch (final Exception e)
284 {
285 throw new RuntimeException("Can't remove NotificationListener " + this, e);
286 }
287 }
288
289 public void handleNotification(
290 final Notification notifIn,
291 final Object handback)
292 {
293 if (notifIn instanceof MBeanServerNotification)
294 {
295 final MBeanServerNotification notif = (MBeanServerNotification) notifIn;
296 final ObjectName objectName = notif.getMBeanName();
297
298 boolean match = false;
299 if ( mObjectName != null && mObjectName.equals(objectName) )
300 {
301 match = true;
302 }
303 else if ( objectName.getDomain().equals( mJMXDomain ) )
304 {
305 if ( mType != null && mType.equals(objectName.getKeyProperty(TYPE_KEY)) )
306 {
307 final String mbeanName = objectName.getKeyProperty(NAME_KEY);
308 if (mName != null && mName.equals(mbeanName))
309 {
310 match = true;
311 }
312 }
313 }
314
315 if ( match )
316 {
317 final String notifType = notif.getType();
318 if (MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(notifType))
319 {
320 mCallback.mbeanRegistered(objectName, this);
321 }
322 else if (MBeanServerNotification.UNREGISTRATION_NOTIFICATION.equals(notifType))
323 {
324 mCallback.mbeanUnregistered(objectName, this);
325 }
326 }
327 }
328 }
329
330 }

mercurial