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