1 /* 2 * Copyright (c) 2000, 2021, 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 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.lang.System.Logger.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 @SuppressWarnings("removal") 113 String form = AccessController.doPrivileged(act); 114 compat = (form != null && form.equals("1.0")); 115 } catch (Exception e) { 116 // OK : Too bad, no compat with 1.0 117 } 118 if (compat) { 119 serialPersistentFields = oldSerialPersistentFields; 120 serialVersionUID = oldSerialVersionUID; 121 } else { 122 serialPersistentFields = newSerialPersistentFields; 123 serialVersionUID = newSerialVersionUID; 124 } 125 } 126 // 127 // END Serialization compatibility stuff 128 129 // 130 // Private members 131 // 132 133 /** 134 * @serial List of {@link ObjectName}s of interest 135 * <ul> 136 * <li><code>null</code> means that all {@link ObjectName}s are implicitly selected 137 * (check for explicit deselections)</li> 138 * <li>Empty vector means that no {@link ObjectName} is explicitly selected</li> 139 * </ul> 140 */ 141 private List<ObjectName> selectedNames = new Vector<ObjectName>(); 142 143 /** 144 * @serial List of {@link ObjectName}s with no interest 145 * <ul> 146 * <li><code>null</code> means that all {@link ObjectName}s are implicitly deselected 147 * (check for explicit selections))</li> 148 * <li>Empty vector means that no {@link ObjectName} is explicitly deselected</li> 149 * </ul> 150 */ 151 private List<ObjectName> deselectedNames = null; 152 153 // 154 // Constructor 155 // 156 157 /** 158 * Creates a filter selecting all MBeanServerNotification notifications for 159 * all ObjectNames. 160 */ MBeanServerNotificationFilter()161 public MBeanServerNotificationFilter() { 162 163 super(); 164 RELATION_LOGGER.log(Level.TRACE, "ENTRY"); 165 166 enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION); 167 enableType(MBeanServerNotification.UNREGISTRATION_NOTIFICATION); 168 169 RELATION_LOGGER.log(Level.TRACE, "RETURN"); 170 return; 171 } 172 173 // 174 // Accessors 175 // 176 177 /** 178 * Disables any MBeanServerNotification (all ObjectNames are 179 * deselected). 180 */ disableAllObjectNames()181 public synchronized void disableAllObjectNames() { 182 183 RELATION_LOGGER.log(Level.TRACE, "ENTRY"); 184 185 selectedNames = new Vector<ObjectName>(); 186 deselectedNames = null; 187 188 RELATION_LOGGER.log(Level.TRACE, "RETURN"); 189 return; 190 } 191 192 /** 193 * Disables MBeanServerNotifications concerning given ObjectName. 194 * 195 * @param objectName ObjectName no longer of interest 196 * 197 * @exception IllegalArgumentException if the given ObjectName is null 198 */ disableObjectName(ObjectName objectName)199 public synchronized void disableObjectName(ObjectName objectName) 200 throws IllegalArgumentException { 201 202 if (objectName == null) { 203 String excMsg = "Invalid parameter."; 204 throw new IllegalArgumentException(excMsg); 205 } 206 207 RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}" + objectName); 208 209 // Removes from selected ObjectNames, if present 210 if (selectedNames != null) { 211 if (selectedNames.size() != 0) { 212 selectedNames.remove(objectName); 213 } 214 } 215 216 // Adds it in deselected ObjectNames 217 if (deselectedNames != null) { 218 // If all are deselected, no need to do anything :) 219 if (!(deselectedNames.contains(objectName))) { 220 // ObjectName was not already deselected 221 deselectedNames.add(objectName); 222 } 223 } 224 225 RELATION_LOGGER.log(Level.TRACE, "RETURN"); 226 return; 227 } 228 229 /** 230 * Enables all MBeanServerNotifications (all ObjectNames are selected). 231 */ enableAllObjectNames()232 public synchronized void enableAllObjectNames() { 233 234 RELATION_LOGGER.log(Level.TRACE, "ENTRY"); 235 236 selectedNames = null; 237 deselectedNames = new Vector<ObjectName>(); 238 239 RELATION_LOGGER.log(Level.TRACE, "RETURN"); 240 return; 241 } 242 243 /** 244 * Enables MBeanServerNotifications concerning given ObjectName. 245 * 246 * @param objectName ObjectName of interest 247 * 248 * @exception IllegalArgumentException if the given ObjectName is null 249 */ enableObjectName(ObjectName objectName)250 public synchronized void enableObjectName(ObjectName objectName) 251 throws IllegalArgumentException { 252 253 if (objectName == null) { 254 String excMsg = "Invalid parameter."; 255 throw new IllegalArgumentException(excMsg); 256 } 257 258 RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", objectName); 259 260 // Removes from deselected ObjectNames, if present 261 if (deselectedNames != null) { 262 if (deselectedNames.size() != 0) { 263 deselectedNames.remove(objectName); 264 } 265 } 266 267 // Adds it in selected ObjectNames 268 if (selectedNames != null) { 269 // If all are selected, no need to do anything :) 270 if (!(selectedNames.contains(objectName))) { 271 // ObjectName was not already selected 272 selectedNames.add(objectName); 273 } 274 } 275 276 RELATION_LOGGER.log(Level.TRACE, "RETURN"); 277 return; 278 } 279 280 /** 281 * Gets all the ObjectNames enabled. 282 * 283 * @return Vector of ObjectNames: 284 * <P>- null means all ObjectNames are implicitly selected, except the 285 * ObjectNames explicitly deselected 286 * <P>- empty means all ObjectNames are deselected, i.e. no ObjectName 287 * selected. 288 */ getEnabledObjectNames()289 public synchronized Vector<ObjectName> getEnabledObjectNames() { 290 if (selectedNames != null) { 291 return new Vector<ObjectName>(selectedNames); 292 } else { 293 return null; 294 } 295 } 296 297 /** 298 * Gets all the ObjectNames disabled. 299 * 300 * @return Vector of ObjectNames: 301 * <P>- null means all ObjectNames are implicitly deselected, except the 302 * ObjectNames explicitly selected 303 * <P>- empty means all ObjectNames are selected, i.e. no ObjectName 304 * deselected. 305 */ getDisabledObjectNames()306 public synchronized Vector<ObjectName> getDisabledObjectNames() { 307 if (deselectedNames != null) { 308 return new Vector<ObjectName>(deselectedNames); 309 } else { 310 return null; 311 } 312 } 313 314 // 315 // NotificationFilter interface 316 // 317 318 /** 319 * Invoked before sending the specified notification to the listener. 320 * <P>If: 321 * <P>- the ObjectName of the concerned MBean is selected (explicitly OR 322 * (implicitly and not explicitly deselected)) 323 * <P>AND 324 * <P>- the type of the operation (registration or unregistration) is 325 * selected 326 * <P>then the notification is sent to the listener. 327 * 328 * @param notif The notification to be sent. 329 * 330 * @return true if the notification has to be sent to the listener, false 331 * otherwise. 332 * 333 * @exception IllegalArgumentException if null parameter 334 */ isNotificationEnabled(Notification notif)335 public synchronized boolean isNotificationEnabled(Notification notif) 336 throws IllegalArgumentException { 337 338 if (notif == null) { 339 String excMsg = "Invalid parameter."; 340 throw new IllegalArgumentException(excMsg); 341 } 342 343 RELATION_LOGGER.log(Level.TRACE, "ENTRY {0}", notif); 344 345 // Checks the type first 346 String ntfType = notif.getType(); 347 Vector<String> enabledTypes = getEnabledTypes(); 348 if (!(enabledTypes.contains(ntfType))) { 349 RELATION_LOGGER.log(Level.TRACE, 350 "Type not selected, exiting"); 351 return false; 352 } 353 354 // We have a MBeanServerNotification: downcasts it 355 MBeanServerNotification mbsNtf = (MBeanServerNotification)notif; 356 357 // Checks the ObjectName 358 ObjectName objName = mbsNtf.getMBeanName(); 359 // Is it selected? 360 boolean isSelectedFlg = false; 361 if (selectedNames != null) { 362 // Not all are implicitly selected: 363 // checks for explicit selection 364 if (selectedNames.size() == 0) { 365 // All are explicitly not selected 366 RELATION_LOGGER.log(Level.TRACE, 367 "No ObjectNames selected, exiting"); 368 return false; 369 } 370 371 isSelectedFlg = selectedNames.contains(objName); 372 if (!isSelectedFlg) { 373 // Not in the explicit selected list 374 RELATION_LOGGER.log(Level.TRACE, 375 "ObjectName not in selected list, exiting"); 376 return false; 377 } 378 } 379 380 if (!isSelectedFlg) { 381 // Not explicitly selected: is it deselected? 382 383 if (deselectedNames == null) { 384 // All are implicitly deselected and it is not explicitly 385 // selected 386 RELATION_LOGGER.log(Level.TRACE, 387 "ObjectName not selected, and all " + 388 "names deselected, exiting"); 389 return false; 390 391 } else if (deselectedNames.contains(objName)) { 392 // Explicitly deselected 393 RELATION_LOGGER.log(Level.TRACE, 394 "ObjectName explicitly not selected, exiting"); 395 return false; 396 } 397 } 398 399 RELATION_LOGGER.log(Level.TRACE, 400 "ObjectName selected, exiting"); 401 return true; 402 } 403 404 405 /** 406 * Deserializes an {@link MBeanServerNotificationFilter} from an {@link ObjectInputStream}. 407 */ readObject(ObjectInputStream in)408 private void readObject(ObjectInputStream in) 409 throws IOException, ClassNotFoundException { 410 if (compat) 411 { 412 // Read an object serialized in the old serial form 413 // 414 ObjectInputStream.GetField fields = in.readFields(); 415 selectedNames = cast(fields.get("mySelectObjNameList", null)); 416 if (fields.defaulted("mySelectObjNameList")) 417 { 418 throw new NullPointerException("mySelectObjNameList"); 419 } 420 deselectedNames = cast(fields.get("myDeselectObjNameList", null)); 421 if (fields.defaulted("myDeselectObjNameList")) 422 { 423 throw new NullPointerException("myDeselectObjNameList"); 424 } 425 } 426 else 427 { 428 // Read an object serialized in the new serial form 429 // 430 in.defaultReadObject(); 431 } 432 } 433 434 435 /** 436 * Serializes an {@link MBeanServerNotificationFilter} to an {@link ObjectOutputStream}. 437 */ writeObject(ObjectOutputStream out)438 private void writeObject(ObjectOutputStream out) 439 throws IOException { 440 if (compat) 441 { 442 // Serializes this instance in the old serial form 443 // 444 ObjectOutputStream.PutField fields = out.putFields(); 445 fields.put("mySelectObjNameList", selectedNames); 446 fields.put("myDeselectObjNameList", deselectedNames); 447 out.writeFields(); 448 } 449 else 450 { 451 // Serializes this instance in the new serial form 452 // 453 out.defaultWriteObject(); 454 } 455 } 456 } 457