001 /***************************************************************************** 002 * Copyright (C) NanoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Original code by Michael Ward * 009 *****************************************************************************/ 010 011 package org.picocontainer.gems.jmx; 012 013 import java.util.HashSet; 014 import java.util.Set; 015 016 import javax.management.DynamicMBean; 017 import javax.management.JMException; 018 import javax.management.MBeanServer; 019 import javax.management.ObjectInstance; 020 import javax.management.ObjectName; 021 022 import org.picocontainer.ComponentAdapter; 023 import org.picocontainer.PicoContainer; 024 import org.picocontainer.visitors.TraversalCheckingVisitor; 025 026 027 /** 028 * A {@link org.picocontainer.PicoVisitor} to register JMX components for components of a {@link PicoContainer} tree in 029 * a {@link MBeanServer}. 030 * @author Michael Ward 031 * @author Jörg Schaible 032 */ 033 public class JMXVisitor extends TraversalCheckingVisitor { 034 private final DynamicMBeanProvider[] mBeanProviders; 035 private final MBeanServer mBeanServer; 036 private final Set visited; 037 private final Set registeredInfo; 038 private PicoContainer picoContainer; 039 040 /** 041 * Construct a JMXVisitor. This instance will register by default any component in the {@link MBeanServer}, that is 042 * already a {@link DynamicMBean}. The {@link ObjectName} will use the default domain of the MBeanServer and has a 043 * <em>type</em> key with the class name (without package name) as value. 044 * @param server The {@link MBeanServer}to use for registering the MBeans. 045 */ 046 public JMXVisitor(final MBeanServer server) { 047 this(server, new DynamicMBeanProvider[]{new DynamicMBeanComponentProvider()}); 048 } 049 050 /** 051 * Construct a JMXVisitor. 052 * @param server The {@link MBeanServer} to use for registering the MBeans. 053 * @param providers The providers to deliver the DynamicMBeans. 054 */ 055 public JMXVisitor(final MBeanServer server, final DynamicMBeanProvider[] providers) { 056 if (server == null) { 057 throw new NullPointerException("MBeanServer may not be null"); 058 } 059 if (providers == null) { 060 throw new NullPointerException("DynamicMBeanProvider[] may not be null"); 061 } 062 if (providers.length == 0) { 063 throw new IllegalArgumentException("DynamicMBeanProvider[] may not be empty"); 064 } 065 mBeanServer = server; 066 mBeanProviders = providers; 067 visited = new HashSet(); 068 registeredInfo = new HashSet(); 069 } 070 071 /** 072 * Entry point for the visitor traversal. 073 * @return Returns a {@link Set} with all ObjectInstance instances retrieved from the {@link MBeanServer} for the 074 * registered MBeans. 075 * @see org.picocontainer.visitors.AbstractPicoVisitor#traverse(java.lang.Object) 076 */ 077 @Override 078 public Object traverse(final Object node) { 079 super.traverse(node); 080 picoContainer = null; 081 final Set set = new HashSet(registeredInfo); 082 registeredInfo.clear(); 083 return set; 084 } 085 086 /** 087 * Provides the PicoContainer, that can resolve the components to register as MBean. 088 * @see org.picocontainer.PicoVisitor#visitContainer(org.picocontainer.PicoContainer) 089 */ 090 @Override 091 public boolean visitContainer(final PicoContainer pico) { 092 super.visitContainer(pico); 093 picoContainer = pico; 094 visited.clear(); 095 return CONTINUE_TRAVERSAL; 096 } 097 098 /** 099 * Register the component as MBean. The implementation uses the known DynamicMBeanProvider instances to get the 100 * MBean from the component. 101 * @see org.picocontainer.PicoVisitor#visitComponentAdapter(org.picocontainer.ComponentAdapter) 102 */ 103 @Override 104 public void visitComponentAdapter(final ComponentAdapter componentAdapter) { 105 super.visitComponentAdapter(componentAdapter); 106 if (picoContainer == null) { 107 throw new JMXRegistrationException("Cannot start JMXVisitor traversal with a ComponentAdapter"); 108 } 109 if (!visited.contains(componentAdapter.getComponentKey())) { 110 visited.add(componentAdapter.getComponentKey()); 111 for (final DynamicMBeanProvider provider : mBeanProviders) { 112 final JMXRegistrationInfo info = provider.provide(picoContainer, componentAdapter); 113 if (info != null) { 114 registeredInfo.add(register(info.getMBean(), info.getObjectName())); 115 break; 116 } 117 } 118 } 119 120 } 121 122 /** 123 * Register a MBean in the MBeanServer. 124 * @param dynamicMBean the {@link DynamicMBean} to register. 125 * @param objectName the {@link ObjectName} of the MBean registered the {@link MBeanServer}. 126 * @return Returns the {@link ObjectInstance} returned from the MBeanServer after registration. 127 * @throws JMXRegistrationException Thrown if MBean cannot be registered. 128 */ 129 protected ObjectInstance register(final DynamicMBean dynamicMBean, final ObjectName objectName) 130 throws JMXRegistrationException { 131 try { 132 return mBeanServer.registerMBean(dynamicMBean, objectName); 133 } catch (final JMException e) { 134 throw new JMXRegistrationException("Unable to register MBean to MBean Server", e); 135 } 136 } 137 }