Merge "Remove raw references to Map in XSQL"
[controller.git] / opendaylight / config / config-manager / src / main / java / org / opendaylight / controller / config / manager / impl / jmx / InternalJMXRegistrator.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.config.manager.impl.jmx;
9
10 import java.io.Closeable;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
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;
27
28 public class InternalJMXRegistrator implements Closeable {
29     private static final Logger LOG = LoggerFactory
30             .getLogger(InternalJMXRegistrator.class);
31     private final MBeanServer configMBeanServer;
32
33     public InternalJMXRegistrator(MBeanServer configMBeanServer) {
34         this.configMBeanServer = configMBeanServer;
35     }
36
37     static class InternalJMXRegistration implements AutoCloseable {
38         private final InternalJMXRegistrator internalJMXRegistrator;
39         private final ObjectName on;
40
41         InternalJMXRegistration(InternalJMXRegistrator internalJMXRegistrator,
42                                 ObjectName on) {
43             this.internalJMXRegistrator = internalJMXRegistrator;
44             this.on = on;
45         }
46
47         @Override
48         public void close() {
49             internalJMXRegistrator.unregisterMBean(on);
50         }
51     }
52
53     @GuardedBy("this")
54     private final Set<ObjectName> registeredObjectNames = new HashSet<>();
55     @GuardedBy("this")
56     private final List<InternalJMXRegistrator> children = new ArrayList<>();
57
58     public synchronized InternalJMXRegistration registerMBean(Object object,
59                                                               ObjectName on) throws InstanceAlreadyExistsException {
60         try {
61             configMBeanServer.registerMBean(object, on);
62         } catch (MBeanRegistrationException | NotCompliantMBeanException e) {
63             throw new IllegalStateException(e);
64         }
65         registeredObjectNames.add(on);
66         return new InternalJMXRegistration(this, on);
67     }
68
69     private synchronized void unregisterMBean(ObjectName on) {
70         // first check that on was registered using this instance
71         boolean removed = registeredObjectNames.remove(on);
72         if (!removed) {
73             throw new IllegalStateException("Cannot unregister - ObjectName not found in 'registeredObjectNames': " + on);
74         }
75         try {
76             configMBeanServer.unregisterMBean(on);
77         } catch (InstanceNotFoundException | MBeanRegistrationException e) {
78             throw new IllegalStateException(e);
79         }
80     }
81
82     public synchronized InternalJMXRegistrator createChild() {
83         InternalJMXRegistrator child = new InternalJMXRegistrator(configMBeanServer);
84         children.add(child);
85         return child;
86     }
87
88     /**
89      * Allow close to be called multiple times.
90      */
91     @Override
92     public synchronized void close() {
93         // close children
94         for (InternalJMXRegistrator child : children) {
95             child.close();
96         }
97         // close registered ONs
98         for (ObjectName on : registeredObjectNames) {
99             try {
100                 configMBeanServer.unregisterMBean(on);
101             } catch (Exception e) {
102                 LOG.warn("Ignoring error while unregistering {}", on, e);
103             }
104         }
105         registeredObjectNames.clear();
106     }
107
108     public <T> T newMBeanProxy(ObjectName objectName, Class<T> interfaceClass) {
109         return JMX.newMBeanProxy(configMBeanServer, objectName, interfaceClass);
110     }
111
112     public <T> T newMBeanProxy(ObjectName objectName, Class<T> interfaceClass,
113                                boolean notificationBroadcaster) {
114         return JMX.newMBeanProxy(configMBeanServer, objectName, interfaceClass,
115                 notificationBroadcaster);
116     }
117
118     public <T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass) {
119         return JMX
120                 .newMXBeanProxy(configMBeanServer, objectName, interfaceClass);
121     }
122
123     public <T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass,
124                                 boolean notificationBroadcaster) {
125         return JMX.newMXBeanProxy(configMBeanServer, objectName,
126                 interfaceClass, notificationBroadcaster);
127     }
128
129     public Set<ObjectName> getRegisteredObjectNames() {
130         return Collections.unmodifiableSet(registeredObjectNames);
131     }
132
133     public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
134         Set<ObjectName> result = configMBeanServer.queryNames(name, query);
135         // keep only those that were registered using this instance
136         return getSameNames(result);
137     }
138
139     private synchronized Set<ObjectName> getSameNames(Set<ObjectName> superSet) {
140         Set<ObjectName> result = new HashSet<>(superSet);
141         result.retainAll(registeredObjectNames);
142         for (InternalJMXRegistrator child : children) {
143             result.addAll(child.getSameNames(superSet));
144         }
145         return result;
146     }
147
148 }