2 * Copyright (c) 2013, 2017 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': %s",
95 getMBeanServer().unregisterMBean(on);
96 } catch (final InstanceNotFoundException e) {
97 LOG.warn("MBean {} not found on server", on, e);
98 } catch (final MBeanRegistrationException e) {
99 throw new IllegalStateException("Failed to unregister MBean " + on, e);
103 public final synchronized InternalJMXRegistrator createChild() {
104 final Nested child = new Nested(this);
110 * Allow close to be called multiple times.
113 public void close() {
117 public final <T> T newMBeanProxy(final ObjectName objectName, final Class<T> interfaceClass) {
118 return JMX.newMBeanProxy(getMBeanServer(), objectName, interfaceClass);
121 public final <T> T newMBeanProxy(final ObjectName objectName, final Class<T> interfaceClass,
122 final boolean notificationBroadcaster) {
123 return JMX.newMBeanProxy(getMBeanServer(), objectName, interfaceClass, notificationBroadcaster);
126 public final <T> T newMXBeanProxy(final ObjectName objectName, final Class<T> interfaceClass) {
127 return JMX.newMXBeanProxy(getMBeanServer(), objectName, interfaceClass);
130 public final <T> T newMXBeanProxy(final ObjectName objectName, final Class<T> interfaceClass,
131 final boolean notificationBroadcaster) {
132 return JMX.newMXBeanProxy(getMBeanServer(), objectName, interfaceClass, notificationBroadcaster);
135 public final Set<ObjectName> getRegisteredObjectNames() {
136 return Collections.unmodifiableSet(registeredObjectNames);
139 public final Set<ObjectName> queryNames(final ObjectName name, final QueryExp query) {
140 // keep only those that were registered using this instance
141 return getSameNames(getMBeanServer().queryNames(name, query));
144 abstract MBeanServer getMBeanServer();
146 synchronized void removeChild(final InternalJMXRegistrator child) {
147 children.remove(child);
150 private synchronized void internalClose() {
151 // close all children
152 for (InternalJMXRegistrator child : children) {
153 // This bypasses the call to removeChild(), preventing a potential deadlock when children are being closed
155 child.internalClose();
159 // close registered ONs
160 for (ObjectName on : registeredObjectNames) {
162 getMBeanServer().unregisterMBean(on);
163 } catch (final InstanceNotFoundException | MBeanRegistrationException e) {
164 LOG.warn("Ignoring error while unregistering {}", on, e);
167 registeredObjectNames.clear();
170 private synchronized Set<ObjectName> getSameNames(final Set<ObjectName> superSet) {
171 final Set<ObjectName> result = new HashSet<>(superSet);
172 result.retainAll(registeredObjectNames);
174 for (InternalJMXRegistrator child : children) {
175 result.addAll(child.getSameNames(superSet));