1 9 package org.jboss.mx.remoting.tracker; 10 11 import java.lang.reflect.UndeclaredThrowableException ; 12 import java.util.ArrayList ; 13 import java.util.Collection ; 14 import java.util.Collections ; 15 import java.util.HashMap ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.Set ; 21 import javax.management.AttributeChangeNotification ; 22 import javax.management.InstanceNotFoundException ; 23 import javax.management.MBeanException ; 24 import javax.management.MBeanServer ; 25 import javax.management.MBeanServerNotification ; 26 import javax.management.Notification ; 27 import javax.management.NotificationBroadcaster ; 28 import javax.management.NotificationFilter ; 29 import javax.management.NotificationListener ; 30 import javax.management.ObjectInstance ; 31 import javax.management.ObjectName ; 32 import javax.management.QueryExp ; 33 import javax.management.ReflectionException ; 34 import org.jboss.logging.Logger; 35 import org.jboss.mx.remoting.JMXUtil; 36 import org.jboss.mx.remoting.MBeanLocator; 37 import org.jboss.mx.remoting.MBeanServerLocator; 38 import org.jboss.mx.remoting.event.ClassQueryExp; 39 import org.jboss.mx.remoting.event.CompositeEventFilter; 40 import org.jboss.mx.remoting.event.CompositeQueryExp; 41 import org.jboss.remoting.ConnectionFailedException; 42 import org.jboss.remoting.ident.Identity; 43 import org.jboss.remoting.network.NetworkInstance; 44 import org.jboss.remoting.network.NetworkNotification; 45 import org.jboss.remoting.network.NetworkRegistryFinder; 46 import org.jboss.remoting.network.NetworkRegistryMBean; 47 48 import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt; 49 50 56 public class MBeanTracker implements NotificationListener 57 { 58 private static final boolean logEvents = Boolean.getBoolean("jboss.mx.tracker.debug"); 59 private static final transient Logger log = Logger.getLogger(MBeanTracker.class.getName()); 60 private final QueryExp query; 61 private final boolean localOnly; 62 private final boolean wantNotifications; 63 private final NotificationFilter filter; 64 private final SynchronizedInt count = new SynchronizedInt(0); 65 private final Map mbeans = new HashMap (); 66 private final String classes[]; 67 private final List actions = new ArrayList (1); 68 private final ObjectName networkRegistry; 69 private final MBeanServer myserver; 70 71 public MBeanTracker(MBeanServer myserver, Class cl[], QueryExp query, boolean localOnly, MBeanTrackerAction action) 72 throws Exception 73 { 74 this(myserver, cl, query, localOnly, null, false, new MBeanTrackerAction[]{action}); 75 } 76 77 public MBeanTracker(MBeanServer myserver, Class cl[], QueryExp query, boolean localOnly, MBeanTrackerAction actions[]) 78 throws Exception 79 { 80 this(myserver, cl, query, localOnly, null, false, actions); 81 } 82 83 public MBeanTracker(MBeanServer myserver, Class cl[], boolean localOnly, MBeanTrackerAction action) 84 throws Exception 85 { 86 this(myserver, cl, null, localOnly, null, false, new MBeanTrackerAction[]{action}); 87 } 88 89 public MBeanTracker(MBeanServer myserver, Class cl[], boolean localOnly, MBeanTrackerAction actions[]) 90 throws Exception 91 { 92 this(myserver, cl, null, localOnly, null, false, actions); 93 } 94 95 public MBeanTracker(MBeanServer myserver, Class cl[], QueryExp query, boolean localOnly, NotificationFilter filter, boolean wantNotifications, MBeanTrackerAction action) 96 throws Exception 97 { 98 this(myserver, cl, query, localOnly, filter, wantNotifications, new MBeanTrackerAction[]{action}); 99 } 100 101 public MBeanTracker(MBeanServer myserver, Class cl[], QueryExp query, boolean localOnly, NotificationFilter filter, boolean wantNotifications) 102 throws Exception 103 { 104 this(myserver, cl, query, localOnly, filter, wantNotifications, (MBeanTrackerAction[]) null); 105 } 106 107 119 public MBeanTracker(MBeanServer myserver, Class cl[], QueryExp query, boolean localOnly, NotificationFilter filter, boolean wantNotifications, MBeanTrackerAction actions[]) 120 throws Exception 121 { 122 this.localOnly = localOnly; 123 this.wantNotifications = wantNotifications; 124 this.filter = filter; 125 this.myserver = myserver; 126 127 if(log.isTraceEnabled()) 128 { 129 StringBuffer buf = new StringBuffer ("creating an MBeanTracker with the following parameters:\n"); 130 buf.append("==========================================\n"); 131 buf.append("MBeanServer: " + myserver + "\n"); 132 if(cl == null) 133 { 134 buf.append("classes: none\n"); 135 } 136 else 137 { 138 for(int c = 0; c < cl.length; c++) 139 { 140 buf.append("classes[" + c + "] " + cl[c].getName() + "\n"); 141 } 142 } 143 log.debug("QueryExp: " + query + "\n"); 144 log.debug("localOnly: " + localOnly + "\n"); 145 log.debug("filter: " + filter + "\n"); 146 log.debug("notifications: " + wantNotifications + "\n"); 147 148 if(actions == null) 149 { 150 log.debug("actions: none\n"); 151 } 152 else 153 { 154 for(int c = 0; c < actions.length; c++) 155 { 156 log.debug("actions[" + c + "]: " + actions[c] + "\n"); 157 } 158 } 159 buf.append("==========================================\n"); 160 log.debug(buf.toString()); 161 } 162 163 if(actions != null) 165 { 166 for(int c = 0; c < actions.length; c++) 167 { 168 if(actions[c] != null) 169 { 170 addActionListener(actions[c]); 171 } 172 } 173 } 174 if(cl != null) 175 { 176 this.classes = new String [cl.length]; 177 for(int c = 0; c < cl.length; c++) 178 { 179 classes[c] = cl[c].getName(); 180 } 181 } 182 else 183 { 184 this.classes = null; 185 } 186 if(query == null && cl != null) 187 { 188 this.query = new ClassQueryExp(cl); 189 } 190 else 191 { 192 if(cl != null) 193 { 194 this.query = new CompositeQueryExp(new QueryExp []{new ClassQueryExp(cl, ClassQueryExp.OR), query}); 195 } 196 else 197 { 198 this.query = query; 199 } 200 } 201 networkRegistry = NetworkRegistryFinder.find(myserver); 203 if(networkRegistry == null) 204 { 205 throw new Exception ("NetworkRegistryMBean not found - MBeanTracker has a dependency on this MBean"); 206 } 207 208 foundMBeanServer(new MBeanServerLocator(Identity.get(myserver))); 209 210 if(this.localOnly == false) 211 { 212 myserver.addNotificationListener(networkRegistry, this, null, null); 214 215 NetworkInstance instances[] = (NetworkInstance[]) myserver.getAttribute(networkRegistry, "Servers"); 217 218 if(instances != null) 219 { 220 for(int c = 0; c < instances.length; c++) 221 { 222 foundMBeanServer(new MBeanServerLocator(instances[c].getIdentity())); 223 } 224 } 225 } 226 } 227 228 234 public void addActionListener(MBeanTrackerAction action) 235 { 236 addActionListener(action, true); 237 } 238 239 245 public void addActionListener(MBeanTrackerAction action, boolean autoinitialregister) 246 { 247 if(log.isTraceEnabled()) 248 { 249 log.debug("adding action: " + action + ", autoinitialregister:" + autoinitialregister); 250 } 251 252 synchronized(actions) 253 { 254 actions.add(action); 255 } 256 if(autoinitialregister) 257 { 258 Set set = getMBeans(); 259 Iterator iter = set.iterator(); 260 while(iter.hasNext()) 261 { 262 MBeanLocator locator = (MBeanLocator) iter.next(); 263 fireRegister(locator); 264 } 265 } 266 } 267 268 273 public void removeActionListener(MBeanTrackerAction action) 274 { 275 if(log.isTraceEnabled()) 276 { 277 log.debug("removing action: " + action); 278 } 279 280 Iterator iter = actions(); 281 while(iter.hasNext()) 282 { 283 MBeanTrackerAction _action = (MBeanTrackerAction) iter.next(); 284 if(_action.equals(action)) 285 { 286 iter.remove(); 287 } 288 } 289 } 290 291 private NotificationFilter createFilterForServer(String id) 292 { 293 NotificationFilter serverfilter = null; 294 NotificationFilter nfilter = new MBeanTrackerFilter(id, classes, wantNotifications); 295 if(filter == null) 296 { 297 serverfilter = nfilter; 298 } 299 else 300 { 301 serverfilter = new CompositeEventFilter(new NotificationFilter []{nfilter, filter}); 302 } 303 return serverfilter; 304 } 305 306 protected void finalize() throws Throwable 307 { 308 destroy(); 309 super.finalize(); 310 } 311 312 315 public void destroy() 316 { 317 if(log.isTraceEnabled()) 318 { 319 log.debug("destroy"); 320 } 321 try 322 { 323 myserver.removeNotificationListener(networkRegistry, this); 324 } 325 catch(Throwable ex) 326 { 327 } 328 } 329 330 335 public final boolean isEmpty() 336 { 337 return count() <= 0; 338 } 339 340 345 public final int count() 346 { 347 return count.get(); 348 } 349 350 355 public final Set getMBeans() 356 { 357 Set set = new HashSet (); 358 synchronized(mbeans) 359 { 360 Iterator iter = mbeans.values().iterator(); 361 while(iter.hasNext()) 362 { 363 Set beans = (Set ) iter.next(); 364 set.addAll(beans); 365 } 366 } 367 return set; 368 } 369 370 375 public final Iterator iterator() 376 { 377 return getMBeans().iterator(); 378 } 379 380 381 private void tryAddListener(MBeanServerLocator server, ObjectName mbean) 382 { 383 try 384 { 385 if(server.getMBeanServer().isInstanceOf(mbean, NotificationBroadcaster .class.getName()) && 386 server.getMBeanServer().isInstanceOf(mbean, NetworkRegistryMBean.class.getName()) == false) 387 { 388 server.getMBeanServer().addNotificationListener(mbean, this, createFilterForServer(server.getServerId()), server); 389 if(log.isTraceEnabled()) 390 { 391 log.debug("added notification listener to: " + mbean + " on server: " + server); 392 } 393 } 394 } 395 catch(Throwable e) 396 { 397 log.error("Error registering listener for server:" + server + " and mbean:" + mbean, e); 398 } 399 } 400 401 407 private void tryRemoveListener(MBeanServerLocator server, ObjectName mbean) 408 { 409 try 410 { 411 if(server.getMBeanServer() == null) 412 { 413 return; 414 } 415 if(server.getMBeanServer().isInstanceOf(mbean, NotificationBroadcaster .class.getName()) && 416 server.getMBeanServer().isInstanceOf(mbean, NetworkRegistryMBean.class.getName()) == false) 417 { 418 server.getMBeanServer().removeNotificationListener(mbean, this); 419 if(log.isTraceEnabled()) 420 { 421 log.debug("removed notification listener to: " + mbean + " on server: " + server); 422 } 423 } 424 } 425 catch(javax.management.InstanceNotFoundException nf) 426 { 427 } 430 catch(ConnectionFailedException cnf) 431 { 432 } 434 catch(Exception e) 435 { 436 if(e instanceof UndeclaredThrowableException ) 437 { 438 UndeclaredThrowableException ut = (UndeclaredThrowableException ) e; 439 if(ut.getUndeclaredThrowable() instanceof ReflectionException ) 440 { 441 ReflectionException re = (ReflectionException ) ut.getUndeclaredThrowable(); 442 if(re.getTargetException() instanceof InstanceNotFoundException || 443 re.getTargetException() instanceof ConnectionFailedException) 444 { 445 return; 447 } 448 } 449 else if(ut.getUndeclaredThrowable() instanceof MBeanException ) 450 { 451 MBeanException mbe = (MBeanException ) ut.getUndeclaredThrowable(); 452 if(mbe.getTargetException() instanceof ConnectionFailedException) 453 { 454 return; 456 } 457 } 458 } 459 if(e instanceof MBeanException ) 460 { 461 MBeanException mbe = (MBeanException ) e; 462 if(mbe.getTargetException() instanceof ConnectionFailedException) 463 { 464 return; 466 } 467 } 468 log.warn("Error removing listener for server:" + server + " and mbean:" + mbean, e); 469 } 470 } 471 472 478 public void handleNotification(Notification notification, Object o) 479 { 480 if(log.isTraceEnabled()) 481 { 482 log.debug("tracker received notification=" + notification + " with handback=" + o); 483 } 484 try 485 { 486 if(notification instanceof MBeanServerNotification && JMXUtil.getMBeanServerObjectName().equals(notification.getSource())) 487 { 488 MBeanServerNotification n = (MBeanServerNotification ) notification; 489 String type = n.getType(); 490 ObjectName mbean = n.getMBeanName(); 491 if(type.equals(MBeanServerNotification.REGISTRATION_NOTIFICATION)) 492 { 493 addMBean((MBeanServerLocator) o, mbean); 494 } 495 else 496 { 497 removeMBean((MBeanServerLocator) o, mbean); 499 } 500 return; 501 } 502 else if(notification instanceof NetworkNotification) 503 { 504 NetworkNotification nn = (NetworkNotification) notification; 505 String type = nn.getType(); 506 if(type.equals(NetworkNotification.SERVER_ADDED)) 507 { 508 Identity ident = nn.getIdentity(); 510 MBeanServerLocator l = new MBeanServerLocator(ident); 511 foundMBeanServer(l); 512 } 513 else if(type.equals(NetworkNotification.SERVER_REMOVED)) 514 { 515 Identity ident = nn.getIdentity(); 517 MBeanServerLocator l = new MBeanServerLocator(ident); 518 lostMBeanServer(l); 519 } 520 return; 521 } 522 else if(notification instanceof AttributeChangeNotification ) 523 { 524 AttributeChangeNotification ch = (AttributeChangeNotification ) notification; 525 if(ch.getAttributeName().equals("State") && hasActions()) 526 { 527 MBeanServerLocator server = (MBeanServerLocator) o; 528 Object src = ch.getSource(); 529 if(src instanceof ObjectName ) 530 { 531 ObjectName obj = (ObjectName ) src; 532 fireStateChange(new MBeanLocator(server, obj), ((Integer ) ch.getOldValue()).intValue(), ((Integer ) ch.getNewValue()).intValue()); 534 return; 535 } 536 else if(src instanceof MBeanLocator) 537 { 538 fireNotification((MBeanLocator) src, notification, o); 539 return; 540 } 541 } 542 } 543 if(wantNotifications && hasActions()) 544 { 545 MBeanServerLocator server = (MBeanServerLocator) o; 547 if(server != null) 548 { 549 Object src = notification.getSource(); 550 if(src instanceof ObjectName ) 551 { 552 ObjectName obj = (ObjectName ) src; 553 MBeanLocator locator = new MBeanLocator(server, obj); 554 fireNotification(locator, notification, o); 555 return; 556 } 557 else if(src instanceof MBeanLocator) 558 { 559 fireNotification((MBeanLocator) src, notification, o); 560 return; 561 } 562 else 563 { 564 log.debug("Unknown source type for notification: " + src); 565 } 566 } 567 } 568 } 569 catch(Exception e) 570 { 571 log.warn("Error encountered receiving notification: " + notification, e); 572 } 573 } 574 575 580 private boolean hasActions() 581 { 582 synchronized(actions) 583 { 584 return actions.isEmpty() == false; 585 } 586 } 587 588 595 protected void fireNotification(MBeanLocator locator, Notification n, Object o) 596 { 597 Iterator iter = actions(); 598 while(iter.hasNext()) 599 { 600 MBeanTrackerAction action = (MBeanTrackerAction) iter.next(); 601 if(wantNotifications && log.isTraceEnabled()) 602 { 603 log.debug("forwarding tracker notification: " + n + " to action: " + action + " for tracker: " + this); 604 } 605 action.mbeanNotification(locator, n, o); 606 } 607 } 608 609 616 protected void fireStateChange(MBeanLocator locator, int ov, int nv) 617 { 618 Iterator iter = actions(); 619 while(iter.hasNext()) 620 { 621 MBeanTrackerAction action = (MBeanTrackerAction) iter.next(); 622 if(wantNotifications && log.isTraceEnabled()) 623 { 624 log.debug("forwarding tracker state change: " + nv + " [" + ov + "] to action: " + action + " for tracker: " + this); 625 } 626 action.mbeanStateChanged(locator, ov, nv); 627 } 628 } 629 630 636 private final Iterator actions() 637 { 638 synchronized(actions) 639 { 640 if(actions.isEmpty()) 641 { 642 return Collections.EMPTY_LIST.iterator(); 643 } 644 return new ArrayList (actions).iterator(); 645 } 646 } 647 648 653 protected void fireUnregister(MBeanLocator locator) 654 { 655 int c = 0; 656 Iterator iter = actions(); 657 while(iter.hasNext()) 658 { 659 MBeanTrackerAction action = (MBeanTrackerAction) iter.next(); 660 if(logEvents && log.isTraceEnabled()) 661 { 662 log.debug("firing unregister to action [" + (++c) + "] => " + action + " for locator => " + locator); 663 } 664 action.mbeanUnregistered(locator); 665 } 666 } 667 668 673 protected void fireRegister(MBeanLocator locator) 674 { 675 int c = 0; 676 Iterator iter = actions(); 677 while(iter.hasNext()) 678 { 679 MBeanTrackerAction action = (MBeanTrackerAction) iter.next(); 680 if(logEvents && log.isTraceEnabled()) 681 { 682 log.debug("firing register to action [" + (++c) + "] => " + action + " for locator => " + locator); 683 } 684 action.mbeanRegistered(locator); 685 } 686 } 687 688 693 public void foundMBeanServer(MBeanServerLocator theserver) 694 { 695 synchronized(mbeans) 696 { 697 if(mbeans.containsKey(theserver)) 699 { 700 return; 701 } 702 mbeans.put(theserver, new HashSet ()); 703 } 704 705 for(int c = 0; c < 3; c++) 706 { 707 try 708 { 709 theserver.getMBeanServer().addNotificationListener(JMXUtil.getMBeanServerObjectName(), this, createFilterForServer(theserver.getServerId()), theserver); 710 Set beans = theserver.getMBeanServer().queryMBeans(new ObjectName ("*:*"), query); 711 if(beans.isEmpty() == false) 712 { 713 Iterator iter = beans.iterator(); 714 while(iter.hasNext()) 715 { 716 addMBean(theserver, ((ObjectInstance ) iter.next()).getObjectName()); 717 } 718 } 719 else 720 { 721 if(log.isTraceEnabled()) 722 { 723 log.debug("Queried server: " + theserver + ", but found 0 mbeans matching query"); 724 } 725 } 726 727 break; 728 } 729 catch(ConnectionFailedException ce) 730 { 731 if(log.isTraceEnabled()) 732 { 733 log.debug("while trying to add a listener and get info for: " + theserver + ", i lost it", ce); 734 } 735 if(c >= 3) 736 { 737 if(log.isTraceEnabled()) 738 { 739 log.debug("giving up on connection failed after " + c + " attempts... " + theserver); 740 } 741 lostMBeanServer(theserver); 743 } 744 } 745 catch(Exception ex) 746 { 747 log.warn("Exception adding mbeans from server: " + theserver, ex); 748 } 749 } 750 } 751 752 758 private void addMBean(MBeanServerLocator server, ObjectName mbean) 759 { 760 if(log.isTraceEnabled()) 761 { 762 log.debug("addMBean called: " + server + ", mbean: " + mbean); 763 } 764 765 MBeanLocator locator = new MBeanLocator(server, mbean); 766 767 boolean found = false; 768 769 synchronized(mbeans) 770 { 771 Set set = (Set ) mbeans.get(server); 772 if(set != null) 773 { 774 if(set.add(locator)) 775 { 776 count.increment(); 777 found = true; 778 } 779 } 780 781 } 782 783 if(!found) 784 { 785 return; 786 } 787 788 tryAddListener(server, mbean); 789 790 if(hasActions()) 791 { 792 fireRegister(locator); 793 } 794 } 795 796 802 private void removeMBean(MBeanServerLocator server, ObjectName mbean) 803 { 804 if(log.isTraceEnabled()) 805 { 806 log.debug("removeMBean called: " + server + ", mbean: " + mbean); 807 } 808 809 MBeanLocator locator = new MBeanLocator(server, mbean); 810 811 synchronized(mbeans) 812 { 813 Set set = (Set ) mbeans.get(server); 814 if(set != null) 815 { 816 if(set.remove(locator)) 817 { 818 count.decrement(); 820 } 821 else 822 { 823 return; 825 } 826 } 827 } 828 829 tryRemoveListener(server, mbean); 830 831 if(hasActions()) 832 { 833 fireUnregister(locator); 834 } 835 } 836 837 842 public void lostMBeanServer(MBeanServerLocator server) 843 { 844 if(wantNotifications && log.isTraceEnabled()) 845 { 846 log.debug("lostMBeanServer: " + server + " for tracker: " + this); 847 } 848 849 Collection list = null; 850 851 synchronized(mbeans) 852 { 853 list = (Set ) mbeans.remove(server); 854 } 855 if(list != null) 856 { 857 if(log.isTraceEnabled()) 858 { 859 log.debug("lost mbean server = " + server + ", list = " + list); 860 } 861 Iterator iter = list.iterator(); 862 while(iter.hasNext()) 863 { 864 MBeanLocator locator = (MBeanLocator) iter.next(); 865 removeMBean(server, locator.getObjectName()); 866 } 867 list.clear(); 868 list = null; 869 } 870 } 871 872 } | Popular Tags |