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