1 /*
2 * Copyright 2000-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
26 package javax.management.relation;
27
28 import static com.sun.jmx.mbeanserver.Util.cast;
29 import static com.sun.jmx.defaults.JmxProperties.RELATION_LOGGER;
30 import com.sun.jmx.mbeanserver.GetPropertyAction;
31
32 import java.io.IOException;
33 import java.io.ObjectInputStream;
34 import java.io.ObjectOutputStream;
35 import java.io.ObjectStreamField;
36 import java.security.AccessController;
37
38 import java.util.List;
39 import java.util.Vector;
40
41 import javax.management.MBeanServerNotification;
42
43 import javax.management.Notification;
44 import javax.management.NotificationFilterSupport;
45 import javax.management.ObjectName;
46
47 import java.util.List;
48 import java.util.logging.Level;
49 import java.util.Vector;
50
51 /**
52 * Filter for {@link MBeanServerNotification}.
53 * This filter filters MBeanServerNotification notifications by
54 * selecting the ObjectNames of interest and the operations (registration,
55 * unregistration, both) of interest (corresponding to notification
56 * types).
57 *
58 * <p>The <b>serialVersionUID</b> of this class is <code>2605900539589789736L</code>.
59 *
60 * @since 1.5
61 */
62 @SuppressWarnings("serial") // serialVersionUID must be constant
63 public class MBeanServerNotificationFilter extends NotificationFilterSupport {
64
65 // Serialization compatibility stuff:
66 // Two serial forms are supported in this class. The selected form depends
67 // on system property "jmx.serial.form":
68 // - "1.0" for JMX 1.0
69 // - any other value for JMX 1.1 and higher
70 //
71 // Serial version for old serial form
72 private static final long oldSerialVersionUID = 6001782699077323605L;
73 //
74 // Serial version for new serial form
75 private static final long newSerialVersionUID = 2605900539589789736L;
76 //
77 // Serializable fields in old serial form
78 private static final ObjectStreamField[] oldSerialPersistentFields =
79 {
80 new ObjectStreamField("mySelectObjNameList", Vector.class),
81 new ObjectStreamField("myDeselectObjNameList", Vector.class)
82 };
83 //
84 // Serializable fields in new serial form
85 private static final ObjectStreamField[] newSerialPersistentFields =
86 {
87 new ObjectStreamField("selectedNames", List.class),
88 new ObjectStreamField("deselectedNames", List.class)
89 };
90 //
91 // Actual serial version and serial form
92 private static final long serialVersionUID;
93 /**
94 * @serialField selectedNames List List of {@link ObjectName}s of interest
95 * <ul>
96 * <li><code>null</code> means that all {@link ObjectName}s are implicitly selected
97 * (check for explicit deselections)</li>
98 * <li>Empty vector means that no {@link ObjectName} is explicitly selected</li>
99 * </ul>
100 * @serialField deselectedNames List List of {@link ObjectName}s with no interest
101 * <ul>
102 * <li><code>null</code> means that all {@link ObjectName}s are implicitly deselected
103 * (check for explicit selections))</li>
104 * <li>Empty vector means that no {@link ObjectName} is explicitly deselected</li>
105 * </ul>
106 */
107 private static final ObjectStreamField[] serialPersistentFields;
108 private static boolean compat = false;
109 static {
110 try {
111 GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
112 String form = AccessController.doPrivileged(act);
113 compat = (form != null && form.equals("1.0"));
114 } catch (Exception e) {
115 // OK : Too bad, no compat with 1.0
116 }
117 if (compat) {
118 serialPersistentFields = oldSerialPersistentFields;
119 serialVersionUID = oldSerialVersionUID;
120 } else {
121 serialPersistentFields = newSerialPersistentFields;
122 serialVersionUID = newSerialVersionUID;
123 }
124 }
125 //
126 // END Serialization compatibility stuff
127
128 //
129 // Private members
130 //
131
132 /**
133 * @serial List of {@link ObjectName}s of interest
134 * <ul>
135 * <li><code>null</code> means that all {@link ObjectName}s are implicitly selected
136 * (check for explicit deselections)</li>
137 * <li>Empty vector means that no {@link ObjectName} is explicitly selected</li>
138 * </ul>
139 */
140 private List<ObjectName> selectedNames = new Vector<ObjectName>();
141
142 /**
143 * @serial List of {@link ObjectName}s with no interest
144 * <ul>
145 * <li><code>null</code> means that all {@link ObjectName}s are implicitly deselected
146 * (check for explicit selections))</li>
147 * <li>Empty vector means that no {@link ObjectName} is explicitly deselected</li>
148 * </ul>
149 */
150 private List<ObjectName> deselectedNames = null;
151
152 //
153 // Constructor
154 //
155
156 /**
157 * Creates a filter selecting all MBeanServerNotification notifications for
158 * all ObjectNames.
159 */
160 public MBeanServerNotificationFilter() {
161
162 super();
163 RELATION_LOGGER.entering(MBeanServerNotificationFilter.class.getName(),
164 "MBeanServerNotificationFilter");
165
166 enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION);
167 enableType(MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
168
169 RELATION_LOGGER.exiting(MBeanServerNotificationFilter.class.getName(),
170 "MBeanServerNotificationFilter");
171 return;
172 }
173
174 //
175 // Accessors
176 //
177
178 /**
179 * Disables any MBeanServerNotification (all ObjectNames are
180 * deselected).
181 */
182 public synchronized void disableAllObjectNames() {
183
184 RELATION_LOGGER.entering(MBeanServerNotificationFilter.class.getName(),
185 "disableAllObjectNames");
186
187 selectedNames = new Vector<ObjectName>();
188 deselectedNames = null;
189
190 RELATION_LOGGER.exiting(MBeanServerNotificationFilter.class.getName(),
191 "disableAllObjectNames");
192 return;
193 }
194
195 /**
196 * Disables MBeanServerNotifications concerning given ObjectName.
197 *
198 * @param objectName ObjectName no longer of interest
199 *
200 * @exception IllegalArgumentException if the given ObjectName is null
201 */
202 public synchronized void disableObjectName(ObjectName objectName)
203 throws IllegalArgumentException {
204
205 if (objectName == null) {
206 String excMsg = "Invalid parameter.";
207 throw new IllegalArgumentException(excMsg);
208 }
209
210 RELATION_LOGGER.entering(MBeanServerNotificationFilter.class.getName(),
211 "disableObjectName", objectName);
212
213 // Removes from selected ObjectNames, if present
214 if (selectedNames != null) {
215 if (selectedNames.size() != 0) {
216 selectedNames.remove(objectName);
217 }
218 }
219
220 // Adds it in deselected ObjectNames
221 if (deselectedNames != null) {
222 // If all are deselected, no need to do anything :)
223 if (!(deselectedNames.contains(objectName))) {
224 // ObjectName was not already deselected
225 deselectedNames.add(objectName);
226 }
227 }
228
229 RELATION_LOGGER.exiting(MBeanServerNotificationFilter.class.getName(),
230 "disableObjectName");
231 return;
232 }
233
234 /**
235 * Enables all MBeanServerNotifications (all ObjectNames are selected).
236 */
237 public synchronized void enableAllObjectNames() {
238
239 RELATION_LOGGER.entering(MBeanServerNotificationFilter.class.getName(),
240 "enableAllObjectNames");
241
242 selectedNames = null;
243 deselectedNames = new Vector<ObjectName>();
244
245 RELATION_LOGGER.exiting(MBeanServerNotificationFilter.class.getName(),
246 "enableAllObjectNames");
247 return;
248 }
249
250 /**
251 * Enables MBeanServerNotifications concerning given ObjectName.
252 *
253 * @param objectName ObjectName of interest
254 *
255 * @exception IllegalArgumentException if the given ObjectName is null
256 */
257 public synchronized void enableObjectName(ObjectName objectName)
258 throws IllegalArgumentException {
259
260 if (objectName == null) {
261 String excMsg = "Invalid parameter.";
262 throw new IllegalArgumentException(excMsg);
263 }
264
265 RELATION_LOGGER.entering(MBeanServerNotificationFilter.class.getName(),
266 "enableObjectName", objectName);
267
268 // Removes from deselected ObjectNames, if present
269 if (deselectedNames != null) {
270 if (deselectedNames.size() != 0) {
271 deselectedNames.remove(objectName);
272 }
273 }
274
275 // Adds it in selected ObjectNames
276 if (selectedNames != null) {
277 // If all are selected, no need to do anything :)
278 if (!(selectedNames.contains(objectName))) {
279 // ObjectName was not already selected
280 selectedNames.add(objectName);
281 }
282 }
283
284 RELATION_LOGGER.exiting(MBeanServerNotificationFilter.class.getName(),
285 "enableObjectName");
286 return;
287 }
288
289 /**
290 * Gets all the ObjectNames enabled.
291 *
292 * @return Vector of ObjectNames:
293 * <P>- null means all ObjectNames are implicitly selected, except the
294 * ObjectNames explicitly deselected
295 * <P>- empty means all ObjectNames are deselected, i.e. no ObjectName
296 * selected.
297 */
298 public synchronized Vector<ObjectName> getEnabledObjectNames() {
299 if (selectedNames != null) {
300 return new Vector<ObjectName>(selectedNames);
301 } else {
302 return null;
303 }
304 }
305
306 /**
307 * Gets all the ObjectNames disabled.
308 *
309 * @return Vector of ObjectNames:
310 * <P>- null means all ObjectNames are implicitly deselected, except the
311 * ObjectNames explicitly selected
312 * <P>- empty means all ObjectNames are selected, i.e. no ObjectName
313 * deselected.
314 */
315 public synchronized Vector<ObjectName> getDisabledObjectNames() {
316 if (deselectedNames != null) {
317 return new Vector<ObjectName>(deselectedNames);
318 } else {
319 return null;
320 }
321 }
322
323 //
324 // NotificationFilter interface
325 //
326
327 /**
328 * Invoked before sending the specified notification to the listener.
329 * <P>If:
330 * <P>- the ObjectName of the concerned MBean is selected (explicitly OR
331 * (implicitly and not explicitly deselected))
332 * <P>AND
333 * <P>- the type of the operation (registration or unregistration) is
334 * selected
335 * <P>then the notification is sent to the listener.
336 *
337 * @param notif The notification to be sent.
338 *
339 * @return true if the notification has to be sent to the listener, false
340 * otherwise.
341 *
342 * @exception IllegalArgumentException if null parameter
343 */
344 public synchronized boolean isNotificationEnabled(Notification notif)
345 throws IllegalArgumentException {
346
347 if (notif == null) {
348 String excMsg = "Invalid parameter.";
349 throw new IllegalArgumentException(excMsg);
350 }
351
352 RELATION_LOGGER.entering(MBeanServerNotificationFilter.class.getName(),
353 "isNotificationEnabled", notif);
354
355 // Checks the type first
356 String ntfType = notif.getType();
357 Vector enabledTypes = getEnabledTypes();
358 if (!(enabledTypes.contains(ntfType))) {
359 RELATION_LOGGER.logp(Level.FINER,
360 MBeanServerNotificationFilter.class.getName(),
361 "isNotificationEnabled",
362 "Type not selected, exiting");
363 return false;
364 }
365
366 // We have a MBeanServerNotification: downcasts it
367 MBeanServerNotification mbsNtf = (MBeanServerNotification)notif;
368
369 // Checks the ObjectName
370 ObjectName objName = mbsNtf.getMBeanName();
371 // Is it selected?
372 boolean isSelectedFlg = false;
373 if (selectedNames != null) {
374 // Not all are implicitly selected:
375 // checks for explicit selection
376 if (selectedNames.size() == 0) {
377 // All are explicitly not selected
378 RELATION_LOGGER.logp(Level.FINER,
379 MBeanServerNotificationFilter.class.getName(),
380 "isNotificationEnabled",
381 "No ObjectNames selected, exiting");
382 return false;
383 }
384
385 isSelectedFlg = selectedNames.contains(objName);
386 if (!isSelectedFlg) {
387 // Not in the explicit selected list
388 RELATION_LOGGER.logp(Level.FINER,
389 MBeanServerNotificationFilter.class.getName(),
390 "isNotificationEnabled",
391 "ObjectName not in selected list, exiting");
392 return false;
393 }
394 }
395
396 if (!isSelectedFlg) {
397 // Not explicitly selected: is it deselected?
398
399 if (deselectedNames == null) {
400 // All are implicitly deselected and it is not explicitly
401 // selected
402 RELATION_LOGGER.logp(Level.FINER,
403 MBeanServerNotificationFilter.class.getName(),
404 "isNotificationEnabled",
405 "ObjectName not selected, and all " +
406 "names deselected, exiting");
407 return false;
408
409 } else if (deselectedNames.contains(objName)) {
410 // Explicitly deselected
411 RELATION_LOGGER.logp(Level.FINER,
412 MBeanServerNotificationFilter.class.getName(),
413 "isNotificationEnabled",
414 "ObjectName explicitly not selected, exiting");
415 return false;
416 }
417 }
418
419 RELATION_LOGGER.logp(Level.FINER,
420 MBeanServerNotificationFilter.class.getName(),
421 "isNotificationEnabled",
422 "ObjectName selected, exiting");
423 return true;
424 }
425
426
427 /**
428 * Deserializes an {@link MBeanServerNotificationFilter} from an {@link ObjectInputStream}.
429 */
430 private void readObject(ObjectInputStream in)
431 throws IOException, ClassNotFoundException {
432 if (compat)
433 {
434 // Read an object serialized in the old serial form
435 //
436 ObjectInputStream.GetField fields = in.readFields();
437 selectedNames = cast(fields.get("mySelectObjNameList", null));
438 if (fields.defaulted("mySelectObjNameList"))
439 {
440 throw new NullPointerException("mySelectObjNameList");
441 }
442 deselectedNames = cast(fields.get("myDeselectObjNameList", null));
443 if (fields.defaulted("myDeselectObjNameList"))
444 {
445 throw new NullPointerException("myDeselectObjNameList");
446 }
447 }
448 else
449 {
450 // Read an object serialized in the new serial form
451 //
452 in.defaultReadObject();
453 }
454 }
455
456
457 /**
458 * Serializes an {@link MBeanServerNotificationFilter} to an {@link ObjectOutputStream}.
459 */
460 private void writeObject(ObjectOutputStream out)
461 throws IOException {
462 if (compat)
463 {
464 // Serializes this instance in the old serial form
465 //
466 ObjectOutputStream.PutField fields = out.putFields();
467 fields.put("mySelectObjNameList", (Vector)selectedNames);
468 fields.put("myDeselectObjNameList", (Vector)deselectedNames);
469 out.writeFields();
470 }
471 else
472 {
473 // Serializes this instance in the new serial form
474 //
475 out.defaultWriteObject();
476 }
477 }
478 }