2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.config.manager.impl.jmx;
10 import com.google.common.base.Preconditions;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashSet;
14 import java.util.List;
16 import javax.annotation.concurrent.GuardedBy;
17 import javax.management.InstanceAlreadyExistsException;
18 import javax.management.InstanceNotFoundException;
19 import javax.management.JMX;
20 import javax.management.MBeanRegistrationException;
21 import javax.management.MBeanServer;
22 import javax.management.NotCompliantMBeanException;
23 import javax.management.ObjectName;
24 import javax.management.QueryExp;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
28 abstract class InternalJMXRegistrator implements AutoCloseable {
29 private static final class Root extends InternalJMXRegistrator {
30 private final MBeanServer mbeanServer;
32 Root(final MBeanServer mbeanServer) {
33 this.mbeanServer = Preconditions.checkNotNull(mbeanServer);
37 MBeanServer getMBeanServer() {
42 private static final class Nested extends InternalJMXRegistrator {
43 private final InternalJMXRegistrator parent;
45 Nested(final InternalJMXRegistrator parent) {
46 this.parent = Preconditions.checkNotNull(parent);
50 MBeanServer getMBeanServer() {
51 return parent.getMBeanServer();
59 parent.removeChild(this);
64 private static final Logger LOG = LoggerFactory.getLogger(InternalJMXRegistrator.class);
66 private final Set<ObjectName> registeredObjectNames = new HashSet<>(1);
68 private final List<Nested> children = new ArrayList<>();
70 public static InternalJMXRegistrator create(final MBeanServer configMBeanServer) {
71 return new Root(configMBeanServer);
74 public final synchronized InternalJMXRegistration registerMBean(final Object object, final ObjectName on)
75 throws InstanceAlreadyExistsException {
77 getMBeanServer().registerMBean(object, on);
78 } catch (final NotCompliantMBeanException e) {
79 throw new IllegalArgumentException("Object does not comply to JMX", e);
80 } catch (final MBeanRegistrationException e) {
81 throw new IllegalStateException("Failed to register " + on, e);
84 registeredObjectNames.add(on);
85 return new InternalJMXRegistration(this, on);
88 final synchronized void unregisterMBean(final ObjectName on) {
89 // first check that on was registered using this instance
90 boolean removed = registeredObjectNames.remove(on);
91 Preconditions.checkState(removed, "Cannot unregister - ObjectName not found in 'registeredObjectNames': {}", on);
94 getMBeanServer().unregisterMBean(on);
95 } catch (final InstanceNotFoundException e) {
96 LOG.warn("MBean {} not found on server", on, e);
97 } catch (final MBeanRegistrationException e) {
98 throw new IllegalStateException("Failed to unregister MBean " + on, e);
102 public final synchronized InternalJMXRegistrator createChild() {
103 final Nested child = new Nested(this);
109 * Allow close to be called multiple times.
112 public void close() {
116 public final <T> T newMBeanProxy(final ObjectName objectName, final Class<T> interfaceClass) {
117 return JMX.newMBeanProxy(getMBeanServer(), objectName, interfaceClass);
120 public final <T> T newMBeanProxy(final ObjectName objectName, final Class<T> interfaceClass,
121 final boolean notificationBroadcaster) {
122 return JMX.newMBeanProxy(getMBeanServer(), objectName, interfaceClass, notificationBroadcaster);
125 public final <T> T newMXBeanProxy(final ObjectName objectName, final Class<T> interfaceClass) {
126 return JMX.newMXBeanProxy(getMBeanServer(), objectName, interfaceClass);
129 public final <T> T newMXBeanProxy(final ObjectName objectName, final Class<T> interfaceClass,
130 final boolean notificationBroadcaster) {
131 return JMX.newMXBeanProxy(getMBeanServer(), objectName, interfaceClass, notificationBroadcaster);
134 public final Set<ObjectName> getRegisteredObjectNames() {
135 return Collections.unmodifiableSet(registeredObjectNames);
138 public final Set<ObjectName> queryNames(final ObjectName name, final QueryExp query) {
139 // keep only those that were registered using this instance
140 return getSameNames(getMBeanServer().queryNames(name, query));
143 abstract MBeanServer getMBeanServer();
145 synchronized void removeChild(final InternalJMXRegistrator child) {
146 children.remove(child);
149 private synchronized void internalClose() {
150 // close all children
151 for (InternalJMXRegistrator child : children) {
152 // This bypasses the call to removeChild(), preventing a potential deadlock when children are being closed
154 child.internalClose();
158 // close registered ONs
159 for (ObjectName on : registeredObjectNames) {
161 getMBeanServer().unregisterMBean(on);
162 } catch (final Exception e) {
163 LOG.warn("Ignoring error while unregistering {}", on, e);
166 registeredObjectNames.clear();
169 private synchronized Set<ObjectName> getSameNames(final Set<ObjectName> superSet) {
170 final Set<ObjectName> result = new HashSet<>(superSet);
171 result.retainAll(registeredObjectNames);
173 for (InternalJMXRegistrator child : children) {
174 result.addAll(child.getSameNames(superSet));