summaryrefslogtreecommitdiff
path: root/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java')
-rw-r--r--java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java343
1 files changed, 343 insertions, 0 deletions
diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java
new file mode 100644
index 0000000000..8f087ba50c
--- /dev/null
+++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java
@@ -0,0 +1,343 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.jmx;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.management.JMException;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.jmx.mbeans.LoggingManagementMBean;
+import org.apache.qpid.server.jmx.mbeans.UserManagementMBean;
+import org.apache.qpid.server.jmx.mbeans.ServerInformationMBean;
+import org.apache.qpid.server.jmx.mbeans.Shutdown;
+import org.apache.qpid.server.jmx.mbeans.VirtualHostMBean;
+import org.apache.qpid.server.logging.log4j.LoggingManagementFacade;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfigurationChangeListener;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
+import org.apache.qpid.server.plugin.PluginFactory;
+import org.apache.qpid.server.plugin.QpidServiceLoader;
+import org.apache.qpid.server.util.MapValueConverter;
+
+public class JMXManagement extends AbstractPluginAdapter implements ConfigurationChangeListener
+{
+ private static final Logger LOGGER = Logger.getLogger(JMXManagement.class);
+
+ public static final String PLUGIN_TYPE = "MANAGEMENT-JMX";
+
+ // attributes
+ public static final String USE_PLATFORM_MBEAN_SERVER = "usePlatformMBeanServer";
+ public static final String NAME = "name";
+
+ // default values
+ public static final String DEFAULT_NAME = "JMXManagement";
+ public static final boolean DEFAULT_USE_PLATFORM_MBEAN_SERVER = true;
+
+ @SuppressWarnings("serial")
+ private static final Collection<String> AVAILABLE_ATTRIBUTES = Collections.unmodifiableCollection(new HashSet<String>(Plugin.AVAILABLE_ATTRIBUTES){{
+ add(NAME);
+ add(USE_PLATFORM_MBEAN_SERVER);
+ add(PluginFactory.PLUGIN_TYPE);
+ }});
+
+ @SuppressWarnings("serial")
+ private static final Map<String, Object> DEFAULTS = new HashMap<String, Object>(){{
+ put(USE_PLATFORM_MBEAN_SERVER, DEFAULT_USE_PLATFORM_MBEAN_SERVER);
+ put(NAME, DEFAULT_NAME);
+ put(PluginFactory.PLUGIN_TYPE, PLUGIN_TYPE);
+ }};
+
+ @SuppressWarnings("serial")
+ private static final Map<String, Class<?>> ATTRIBUTE_TYPES = new HashMap<String, Class<?>>(){{
+ put(USE_PLATFORM_MBEAN_SERVER, Boolean.class);
+ put(NAME, String.class);
+ put(PluginFactory.PLUGIN_TYPE, String.class);
+ }};
+
+ private final Broker _broker;
+ private JMXManagedObjectRegistry _objectRegistry;
+
+ private final Map<ConfiguredObject, AMQManagedObject> _children = new HashMap<ConfiguredObject, AMQManagedObject>();
+
+ public JMXManagement(UUID id, Broker broker, Map<String, Object> attributes)
+ {
+ super(id, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES), broker.getTaskExecutor());
+ _broker = broker;
+ addParent(Broker.class, broker);
+ }
+
+ @Override
+ protected boolean setState(State currentState, State desiredState)
+ {
+ if(desiredState == State.ACTIVE)
+ {
+ try
+ {
+ start();
+ }
+ catch (JMException e)
+ {
+ throw new RuntimeException("Couldn't start JMX management", e);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Couldn't start JMX management", e);
+ }
+ return true;
+ }
+ else if(desiredState == State.STOPPED)
+ {
+ stop();
+ return true;
+ }
+ return false;
+ }
+
+ private void start() throws JMException, IOException
+ {
+ Port connectorPort = null;
+ Port registryPort = null;
+ Collection<Port> ports = _broker.getPorts();
+ for (Port port : ports)
+ {
+ if (State.QUIESCED.equals(port.getActualState()))
+ {
+ continue;
+ }
+
+ if(isRegistryPort(port))
+ {
+ registryPort = port;
+ }
+ else if(isConnectorPort(port))
+ {
+ connectorPort = port;
+ }
+ }
+ if(connectorPort == null)
+ {
+ throw new IllegalStateException("No JMX connector port found supporting protocol " + Protocol.JMX_RMI);
+ }
+ if(registryPort == null)
+ {
+ throw new IllegalStateException("No JMX RMI port found supporting protocol " + Protocol.RMI);
+ }
+
+ _objectRegistry = new JMXManagedObjectRegistry(_broker, connectorPort, registryPort, this);
+
+ _broker.addChangeListener(this);
+
+ synchronized (_children)
+ {
+ for(VirtualHost virtualHost : _broker.getVirtualHosts())
+ {
+ if(!_children.containsKey(virtualHost))
+ {
+ LOGGER.debug("Create MBean for virtual host:" + virtualHost.getName());
+ VirtualHostMBean mbean = new VirtualHostMBean(virtualHost, _objectRegistry);
+ LOGGER.debug("Check for additional MBeans for virtual host:" + virtualHost.getName());
+ createAdditionalMBeansFromProviders(virtualHost, mbean);
+ }
+ }
+ Collection<AuthenticationProvider> authenticationProviders = _broker.getAuthenticationProviders();
+ for (AuthenticationProvider authenticationProvider : authenticationProviders)
+ {
+ if(authenticationProvider instanceof PasswordCredentialManagingAuthenticationProvider)
+ {
+ UserManagementMBean mbean = new UserManagementMBean(
+ (PasswordCredentialManagingAuthenticationProvider) authenticationProvider,
+ _objectRegistry);
+ _children.put(authenticationProvider, mbean);
+ }
+ }
+ }
+ new Shutdown(_objectRegistry);
+ new ServerInformationMBean(_objectRegistry, _broker);
+ if (LoggingManagementFacade.getCurrentInstance() != null)
+ {
+ new LoggingManagementMBean(LoggingManagementFacade.getCurrentInstance(), _objectRegistry);
+ }
+ _objectRegistry.start();
+ }
+
+ private boolean isConnectorPort(Port port)
+ {
+ return port.getProtocols().contains(Protocol.JMX_RMI);
+ }
+
+ private boolean isRegistryPort(Port port)
+ {
+ return port.getProtocols().contains(Protocol.RMI);
+ }
+
+ private void stop()
+ {
+ synchronized (_children)
+ {
+ for(ConfiguredObject object : _children.keySet())
+ {
+ AMQManagedObject mbean = _children.get(object);
+ if (mbean instanceof ConfigurationChangeListener)
+ {
+ object.removeChangeListener((ConfigurationChangeListener)mbean);
+ }
+ try
+ {
+ mbean.unregister();
+ }
+ catch (JMException e)
+ {
+ LOGGER.error("Error unregistering mbean", e);
+ }
+ }
+ _children.clear();
+ }
+ _broker.removeChangeListener(this);
+ _objectRegistry.close();
+ }
+
+ @Override
+ public void stateChanged(ConfiguredObject object, State oldState, State newState)
+ {
+ // no-op
+ }
+
+ @Override
+ public void childAdded(ConfiguredObject object, ConfiguredObject child)
+ {
+ synchronized (_children)
+ {
+ try
+ {
+ AMQManagedObject mbean;
+ if(child instanceof VirtualHost)
+ {
+ VirtualHost vhostChild = (VirtualHost)child;
+ mbean = new VirtualHostMBean(vhostChild, _objectRegistry);
+ }
+ else if(child instanceof PasswordCredentialManagingAuthenticationProvider)
+ {
+ mbean = new UserManagementMBean((PasswordCredentialManagingAuthenticationProvider) child, _objectRegistry);
+ }
+ else
+ {
+ mbean = null;
+ }
+
+ if (mbean != null)
+ {
+ createAdditionalMBeansFromProviders(child, mbean);
+ }
+ }
+ catch(JMException e)
+ {
+ LOGGER.error("Error creating mbean", e);
+ // TODO - Implement error reporting on mbean creation
+ }
+ }
+ }
+
+ @Override
+ public void childRemoved(ConfiguredObject object, ConfiguredObject child)
+ {
+ // TODO - implement vhost removal (possibly just removing the instanceof check below)
+
+ synchronized (_children)
+ {
+ if(child instanceof PasswordCredentialManagingAuthenticationProvider)
+ {
+ AMQManagedObject mbean = _children.remove(child);
+ if(mbean != null)
+ {
+ try
+ {
+ mbean.unregister();
+ }
+ catch(JMException e)
+ {
+ LOGGER.error("Error creating mbean", e);
+ //TODO - report error on removing child MBean
+ }
+ }
+ }
+
+ }
+ }
+
+ @Override
+ public void attributeSet(ConfiguredObject object, String attributeName, Object oldAttributeValue, Object newAttributeValue)
+ {
+ // no-op
+ }
+
+ private void createAdditionalMBeansFromProviders(ConfiguredObject child, AMQManagedObject mbean) throws JMException
+ {
+ _children.put(child, mbean);
+
+ QpidServiceLoader<MBeanProvider> qpidServiceLoader = new QpidServiceLoader<MBeanProvider>();
+ for (MBeanProvider provider : qpidServiceLoader.instancesOf(MBeanProvider.class))
+ {
+ LOGGER.debug("Consulting mbean provider : " + provider + " for child : " + child);
+ if (provider.isChildManageableByMBean(child))
+ {
+ LOGGER.debug("Provider will create mbean ");
+ provider.createMBean(child, mbean);
+ // TODO track the mbeans that have been created on behalf of a child in a map, then
+ // if the child is ever removed, destroy these beans too.
+ }
+ }
+ }
+
+ /** Added for testing purposes */
+ Broker getBroker()
+ {
+ return _broker;
+ }
+
+ @Override
+ public String getName()
+ {
+ return (String)getAttribute(NAME);
+ }
+
+ @Override
+ public Collection<String> getAttributeNames()
+ {
+ return AVAILABLE_ATTRIBUTES;
+ }
+
+}