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