3b7858c4771c3419f2958415a2e852865f27d851
[controller.git] / opendaylight / config / config-api / src / main / java / org / opendaylight / controller / config / api / jmx / ObjectNameUtil.java
1 /*
2  * Copyright (c) 2013, 2017 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.api.jmx;
9
10 import java.util.Arrays;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.Hashtable;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.Set;
17 import javax.annotation.concurrent.ThreadSafe;
18 import javax.management.MalformedObjectNameException;
19 import javax.management.ObjectName;
20 import org.opendaylight.controller.config.api.ModuleIdentifier;
21 import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
22
23 /**
24  * Provides ObjectName creation. Each created ObjectName consists of domain that
25  * is defined as {@link #ON_DOMAIN} and at least one key-value pair. The only
26  * mandatory property is {@link #TYPE_KEY}. All transaction related mbeans have
27  * {@link #TRANSACTION_NAME_KEY} property set.
28  */
29 @ThreadSafe
30 public final class ObjectNameUtil {
31
32     public static final String ON_DOMAIN = ConfigRegistryConstants.ON_DOMAIN;
33     public static final String MODULE_FACTORY_NAME_KEY = "moduleFactoryName";
34     public static final String SERVICE_QNAME_KEY = "serviceQName";
35     public static final String INSTANCE_NAME_KEY = "instanceName";
36     public static final String TYPE_KEY = ConfigRegistryConstants.TYPE_KEY;
37     public static final String TYPE_CONFIG_TRANSACTION = "ConfigTransaction";
38     public static final String TYPE_MODULE = "Module";
39     public static final String TYPE_SERVICE_REFERENCE = "ServiceReference";
40     public static final String TYPE_RUNTIME_BEAN = "RuntimeBean";
41     public static final String TRANSACTION_NAME_KEY = "TransactionName";
42     public static final String REF_NAME_KEY = "RefName";
43     private static final String REPLACED_QUOTATION_MARK = "\\?";
44     public static final String ON_WILDCARD = "*";
45
46     private ObjectNameUtil() {
47     }
48
49     public static ObjectName createON(final String on) {
50         try {
51             return new ObjectName(on);
52         } catch (final MalformedObjectNameException e) {
53             throw new IllegalArgumentException(e);
54         }
55     }
56
57     public static ObjectName createON(final String name, final String key, final String value) {
58         return ConfigRegistryConstants.createON(name, key, value);
59     }
60
61     public static ObjectName createON(final String domain, final Map<String, String> attribs) {
62         Hashtable<String, String> table = new Hashtable<>(attribs);
63         try {
64             return new ObjectName(domain, table);
65         } catch (final MalformedObjectNameException e) {
66             throw new IllegalArgumentException(e);
67         }
68
69     }
70
71     public static ObjectName createONWithDomainAndType(final String type) {
72         return ConfigRegistryConstants.createONWithDomainAndType(type);
73     }
74
75     public static ObjectName createTransactionControllerON(final String transactionName) {
76         Map<String, String> onParams = new HashMap<>();
77         onParams.put(TRANSACTION_NAME_KEY, transactionName);
78         onParams.put(TYPE_KEY, TYPE_CONFIG_TRANSACTION);
79         return createON(ON_DOMAIN, onParams);
80     }
81
82     public static ObjectName createTransactionModuleON(final String transactionName,
83             final ModuleIdentifier moduleIdentifier) {
84         return createTransactionModuleON(transactionName, moduleIdentifier.getFactoryName(),
85                 moduleIdentifier.getInstanceName());
86     }
87
88     public static ObjectName createTransactionModuleON(final String transactionName, final String moduleName,
89             final String instanceName) {
90         Map<String, String> onParams = createModuleMap(moduleName, instanceName);
91         onParams.put(TRANSACTION_NAME_KEY, transactionName);
92         return createON(ON_DOMAIN, onParams);
93     }
94
95     public static ObjectName createTransactionModuleON(final String transactionName, final ObjectName on) {
96         return createTransactionModuleON(transactionName, getFactoryName(on), getInstanceName(on));
97     }
98
99     public static ObjectName createReadOnlyModuleON(final ModuleIdentifier moduleIdentifier) {
100         return createReadOnlyModuleON(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
101     }
102
103     public static ObjectName createReadOnlyModuleON(final String moduleName, final String instanceName) {
104         Map<String, String> onParams = createModuleMap(moduleName, instanceName);
105         return createON(ON_DOMAIN, onParams);
106     }
107
108     public static ObjectName createReadOnlyServiceON(final String serviceQName, final String refName) {
109         Map<String, String> onParams = createServiceMap(serviceQName, refName);
110         return createON(ON_DOMAIN, onParams);
111     }
112
113     public static ObjectName createTransactionServiceON(final String transactionName, final String serviceQName,
114             final String refName) {
115         Map<String, String> onParams = createServiceON(transactionName, serviceQName, refName);
116         return createON(ON_DOMAIN, onParams);
117     }
118
119     public static String getServiceQName(final ObjectName objectName) {
120         checkType(objectName, TYPE_SERVICE_REFERENCE);
121         String quoted = objectName.getKeyProperty(SERVICE_QNAME_KEY);
122         return unquoteAndUnescape(objectName, quoted);
123     }
124
125     // ObjectName supports quotation and ignores tokens like =, but fails to ignore
126     // ? sign.
127     // It must be replaced with another character that hopefully does not collide
128     // with actual value.
129     private static String unquoteAndUnescape(final ObjectName objectName, final String quoted) {
130         if (quoted == null) {
131             throw new IllegalArgumentException("Cannot find " + SERVICE_QNAME_KEY + " in " + objectName);
132         }
133         if (!quoted.startsWith("\"") || !quoted.endsWith("\"")) {
134             throw new IllegalArgumentException("Quotes not found in " + objectName);
135         }
136         String substring = quoted.substring(1);
137         substring = substring.substring(0, substring.length() - 1);
138         substring = substring.replace(REPLACED_QUOTATION_MARK, "?");
139         return substring;
140     }
141
142     private static String quoteAndEscapeValue(final String serviceQName) {
143         return "\"" + serviceQName.replace("?", REPLACED_QUOTATION_MARK) + "\"";
144     }
145
146     public static String getReferenceName(final ObjectName objectName) {
147         checkType(objectName, TYPE_SERVICE_REFERENCE);
148         return objectName.getKeyProperty(REF_NAME_KEY);
149     }
150
151     private static Map<String, String> createServiceON(final String transactionName, final String serviceQName,
152             final String refName) {
153         Map<String, String> result = new HashMap<>(createServiceMap(serviceQName, refName));
154         result.put(TRANSACTION_NAME_KEY, transactionName);
155         return result;
156     }
157
158     private static Map<String, String> createServiceMap(final String serviceQName, final String refName) {
159         Map<String, String> onParams = new HashMap<>();
160         onParams.put(TYPE_KEY, TYPE_SERVICE_REFERENCE);
161         onParams.put(SERVICE_QNAME_KEY, quoteAndEscapeValue(serviceQName));
162         onParams.put(REF_NAME_KEY, refName);
163         return onParams;
164     }
165
166     private static Map<String, String> createModuleMap(final String moduleName, final String instanceName) {
167         Map<String, String> onParams = new HashMap<>();
168         onParams.put(TYPE_KEY, TYPE_MODULE);
169         onParams.put(MODULE_FACTORY_NAME_KEY, moduleName);
170         onParams.put(INSTANCE_NAME_KEY, instanceName);
171         return onParams;
172     }
173
174     public static String getFactoryName(final ObjectName objectName) {
175         checkTypeOneOf(objectName, TYPE_MODULE, TYPE_RUNTIME_BEAN);
176         return objectName.getKeyProperty(MODULE_FACTORY_NAME_KEY);
177     }
178
179     public static String getInstanceName(final ObjectName objectName) {
180         checkTypeOneOf(objectName, TYPE_MODULE, TYPE_RUNTIME_BEAN);
181         return objectName.getKeyProperty(INSTANCE_NAME_KEY);
182     }
183
184     public static String getTransactionName(final ObjectName objectName) {
185         return objectName.getKeyProperty(TRANSACTION_NAME_KEY);
186     }
187
188     /**
189      * Sanitize on: keep only mandatory attributes of module + metadata.
190      */
191     public static ObjectName withoutTransactionName(final ObjectName inputON) {
192         checkTypeOneOf(inputON, TYPE_MODULE, TYPE_SERVICE_REFERENCE);
193         if (getTransactionName(inputON) == null) {
194             throw new IllegalArgumentException("Expected ObjectName with transaction:" + inputON);
195         }
196         if (!ON_DOMAIN.equals(inputON.getDomain())) {
197             throw new IllegalArgumentException("Expected different domain: " + inputON);
198         }
199         Map<String, String> outputProperties;
200         if (inputON.getKeyProperty(TYPE_KEY).equals(TYPE_MODULE)) {
201             String moduleName = getFactoryName(inputON);
202             String instanceName = getInstanceName(inputON);
203             outputProperties = new HashMap<>(createModuleMap(moduleName, instanceName));
204         } else {
205             String serviceQName = getServiceQName(inputON);
206             String refName = getReferenceName(inputON);
207             outputProperties = new HashMap<>(createServiceMap(serviceQName, refName));
208         }
209         Map<String, String> allProperties = getAdditionalProperties(inputON);
210         for (Entry<String, String> entry : allProperties.entrySet()) {
211             if (entry.getKey().startsWith("X-")) {
212                 outputProperties.put(entry.getKey(), entry.getValue());
213             }
214         }
215         return createON(ON_DOMAIN, outputProperties);
216     }
217
218     public static ObjectName withTransactionName(final ObjectName inputON, final String transactionName) {
219         Map<String, String> additionalProperties = getAdditionalProperties(inputON);
220         additionalProperties.put(TRANSACTION_NAME_KEY, transactionName);
221         return createON(inputON.getDomain(), additionalProperties);
222
223     }
224
225     private static void assertDoesNotContain(final Map<String, String> additionalProperties, final String key) {
226         if (additionalProperties.containsKey(key)) {
227             throw new IllegalArgumentException("Map 'additionalProperties' cannot overwrite attribute " + key);
228         }
229     }
230
231     public static ObjectName createRuntimeBeanName(final String moduleName, final String instanceName,
232             final Map<String, String> additionalProperties) {
233         // check that there is no overwriting of default attributes
234         assertDoesNotContain(additionalProperties, MODULE_FACTORY_NAME_KEY);
235         assertDoesNotContain(additionalProperties, INSTANCE_NAME_KEY);
236         assertDoesNotContain(additionalProperties, TYPE_KEY);
237         assertDoesNotContain(additionalProperties, TRANSACTION_NAME_KEY);
238         Map<String, String> map = new HashMap<>(additionalProperties);
239         map.put(MODULE_FACTORY_NAME_KEY, moduleName);
240         map.put(INSTANCE_NAME_KEY, instanceName);
241         map.put(TYPE_KEY, TYPE_RUNTIME_BEAN);
242         return createON(ON_DOMAIN, map);
243     }
244
245     private static Set<String> blacklist = new HashSet<>(
246             Arrays.asList(MODULE_FACTORY_NAME_KEY, INSTANCE_NAME_KEY, TYPE_KEY));
247
248     public static Map<String, String> getAdditionalPropertiesOfRuntimeBeanName(final ObjectName on) {
249         checkType(on, TYPE_RUNTIME_BEAN);
250         Map<String, String> allProperties = getAdditionalProperties(on);
251         Map<String, String> result = new HashMap<>();
252         for (Entry<String, String> entry : allProperties.entrySet()) {
253             if (!blacklist.contains(entry.getKey())) {
254                 result.put(entry.getKey(), entry.getValue());
255             }
256         }
257         return result;
258     }
259
260     public static Map<String, String> getAdditionalProperties(final ObjectName on) {
261         Map<String, String> keyPropertyList = on.getKeyPropertyList();
262         Map<String, String> result = new HashMap<>();
263         for (Entry<String, String> entry : keyPropertyList.entrySet()) {
264             result.put(entry.getKey(), entry.getValue());
265         }
266         return result;
267     }
268
269     public static void checkDomain(final ObjectName objectName) {
270         if (!ON_DOMAIN.equals(objectName.getDomain())) {
271             throw new IllegalArgumentException("Wrong domain " + objectName);
272         }
273
274     }
275
276     public static void checkType(final ObjectName objectName, final String type) {
277         if (!type.equals(objectName.getKeyProperty(TYPE_KEY))) {
278             throw new IllegalArgumentException("Wrong type, expected '" + type + "', got " + objectName);
279         }
280     }
281
282     public static void checkTypeOneOf(final ObjectName objectName, final String... types) {
283         for (String type : types) {
284             if (type.equals(objectName.getKeyProperty(TYPE_KEY))) {
285                 return;
286             }
287         }
288         throw new IllegalArgumentException(
289                 "Wrong type, expected one of " + Arrays.asList(types) + ", got " + objectName);
290     }
291
292     public static ObjectName createModulePattern(final String moduleName, final String instanceName) {
293         String finalModuleName = moduleName == null ? ON_WILDCARD : moduleName;
294         String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName;
295
296         // do not return object names containing transaction name
297         ObjectName namePattern = ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":" + ObjectNameUtil.TYPE_KEY + "="
298                 + ObjectNameUtil.TYPE_MODULE + "," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + finalModuleName
299                 + "," + "" + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + finalInstanceName);
300         return namePattern;
301     }
302
303     public static ObjectName createModulePattern(final String ifcName, final String instanceName,
304             final String transactionName) {
305         String finalIfcName = ifcName == null ? ON_WILDCARD : ifcName;
306         String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName;
307         String finalTransactionName = transactionName == null ? ON_WILDCARD : transactionName;
308
309         return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":type=Module,"
310                 + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + finalIfcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY
311                 + "=" + finalInstanceName + "," + ObjectNameUtil.TRANSACTION_NAME_KEY + "=" + finalTransactionName);
312     }
313
314     public static ObjectName createRuntimeBeanPattern(final String moduleName, final String instanceName) {
315         String finalModuleName = moduleName == null ? ON_WILDCARD : moduleName;
316         String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName;
317
318         return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":" + ObjectNameUtil.TYPE_KEY + "="
319                 + ObjectNameUtil.TYPE_RUNTIME_BEAN + "," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "="
320                 + finalModuleName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + finalInstanceName + ",*");
321
322     }
323
324     public static ModuleIdentifier fromON(final ObjectName objectName, final String expectedType) {
325         checkType(objectName, expectedType);
326         String factoryName = getFactoryName(objectName);
327         if (factoryName == null) {
328             throw new IllegalArgumentException("ObjectName does not contain module name");
329         }
330         String instanceName = getInstanceName(objectName);
331         if (instanceName == null) {
332             throw new IllegalArgumentException("ObjectName does not contain instance name");
333         }
334         return new ModuleIdentifier(factoryName, instanceName);
335     }
336
337     public static boolean isServiceReference(final ObjectName objectName) {
338         return TYPE_SERVICE_REFERENCE.equals(objectName.getKeyProperty(TYPE_KEY));
339     }
340 }