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