Remove yang-test
[controller.git] / opendaylight / config / config-manager-facade-xml / src / main / java / org / opendaylight / controller / config / facade / xml / rpc / RuntimeRpcElementResolved.java
1 /*
2  * Copyright (c) 2015, 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
9 package org.opendaylight.controller.config.facade.xml.rpc;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Strings;
14 import com.google.common.collect.Maps;
15 import java.util.HashMap;
16 import java.util.Map;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19 import javax.management.ObjectName;
20 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
21 import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.Modules;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.modules.Module;
24
25 /**
26  * Represents parsed xpath to runtime bean instance.
27  */
28 public final class RuntimeRpcElementResolved {
29     private final String moduleName;
30     private final String instanceName;
31     private final String namespace;
32     private final String runtimeBeanName;
33     private final Map<String, String> additionalAttributes;
34
35     private RuntimeRpcElementResolved(String namespace, String moduleName, String instanceName, String runtimeBeanName,
36             Map<String, String> additionalAttributes) {
37         this.moduleName = Preconditions.checkNotNull(moduleName, "Module name");
38         this.instanceName = Preconditions.checkNotNull(instanceName, "Instance name");
39         this.additionalAttributes = additionalAttributes;
40         this.namespace = Preconditions.checkNotNull(namespace, "Namespace");
41         this.runtimeBeanName = Preconditions.checkNotNull(runtimeBeanName, "Runtime bean name");
42     }
43
44     public String getModuleName() {
45         return moduleName;
46     }
47
48     @VisibleForTesting
49     Map<String, String> getAdditionalAttributes() {
50         return additionalAttributes;
51     }
52
53     public String getInstanceName() {
54         return instanceName;
55     }
56
57     public String getNamespace() {
58         return namespace;
59     }
60
61     public String getRuntimeBeanName() {
62         return runtimeBeanName;
63     }
64
65     public ObjectName getObjectName(ModuleRpcs rpcMapping) {
66         Map<String, String> additionalAttributesJavaNames = Maps
67                 .newHashMapWithExpectedSize(additionalAttributes.size());
68         for (String attributeYangName : additionalAttributes.keySet()) {
69             String attributeJavaName = rpcMapping.getRbeJavaName(attributeYangName);
70             Preconditions.checkState(attributeJavaName != null,
71                     "Cannot find java name for runtime bean wtih yang name %s", attributeYangName);
72             additionalAttributesJavaNames.put(attributeJavaName, additionalAttributes.get(attributeYangName));
73         }
74         return ObjectNameUtil.createRuntimeBeanName(moduleName, instanceName, additionalAttributesJavaNames);
75     }
76
77     /**
78      * Pattern for an absolute instance identifier xpath pointing to a runtime bean.
79      * For instance e.g:
80      *
81      * <pre>
82      * /modules/module[name=instanceName][type=moduleType]
83      * </pre>
84      *
85      *<p>
86      * or
87      *
88      * <pre>
89      * /a:modules/a:module[a:name=instanceName][a:type=moduleType]
90      * </pre>
91      */
92     private static final String XPATH_PATTERN_BLUEPRINT = "/" + getRegExForPrefixedName(Modules.QNAME.getLocalName())
93             + "/" + getRegExForPrefixedName(Module.QNAME.getLocalName())
94
95             + "\\[" + "(?<key1>" + getRegExForPrefixedName(XmlMappingConstants.TYPE_KEY) + "|"
96             + getRegExForPrefixedName(XmlMappingConstants.NAME_KEY) + ")" + "=('|\")?(?<value1>[^'\"\\]]+)('|\")?"
97             + "( and |\\]\\[)" + "(?<key2>" + getRegExForPrefixedName(XmlMappingConstants.TYPE_KEY) + "|"
98             + getRegExForPrefixedName(XmlMappingConstants.NAME_KEY) + ")" + "=('|\")?(?<value2>[^'\"\\]]+)('|\")?"
99             + "\\]"
100
101             + "(?<additional>.*)";
102
103     /**
104      * Return reg ex that matches either the name with or without a prefix.
105      */
106     private static String getRegExForPrefixedName(final String name) {
107         return "([^:]+:)?" + name;
108     }
109
110     private static final Pattern XPATH_PATTERN = Pattern.compile(XPATH_PATTERN_BLUEPRINT);
111
112     /**
113      * Pattern for additional path elements inside xpath for instance identifier
114      * pointing to an inner runtime bean. E.g:
115      *
116      * <pre>
117      * /modules/module[name=instanceName and type=moduleType]/inner[key=b]
118      * </pre>
119      */
120     private static final String ADDITIONAL_PATTERN_BLUEPRINT = getRegExForPrefixedName("(?<additionalKey>.+)")
121             + "\\[(?<prefixedKey>" + getRegExForPrefixedName("(.+)")
122             + ")=('|\")?(?<additionalValue>[^'\"\\]]+)('|\")?\\]";
123     private static final Pattern ADDITIONAL_PATTERN = Pattern.compile(ADDITIONAL_PATTERN_BLUEPRINT);
124
125     public static RuntimeRpcElementResolved fromXpath(String xpath, String elementName, String namespace) {
126         Matcher matcher = XPATH_PATTERN.matcher(xpath);
127         Preconditions.checkState(matcher.matches(),
128                 "Node %s with value '%s' not in required form on rpc element %s, required format is %s",
129                 // TODO refactor this string, and/or unify with RPR.CONTEXT_INSTANCE from
130                 // netconf
131                 "context-instance", xpath, elementName, XPATH_PATTERN_BLUEPRINT);
132
133         PatternGroupResolver groups = new PatternGroupResolver(matcher.group("key1"), matcher.group("value1"),
134                 matcher.group("value2"), matcher.group("additional"));
135
136         String moduleName = groups.getModuleName();
137         String instanceName = groups.getInstanceName();
138
139         Map<String, String> additionalAttributes = groups.getAdditionalKeys(elementName, moduleName);
140
141         return new RuntimeRpcElementResolved(namespace, moduleName, instanceName, groups.getRuntimeBeanYangName(),
142                 additionalAttributes);
143     }
144
145     private static final class PatternGroupResolver {
146
147         private final String key1;
148         private final String value1;
149         private final String value2;
150         private final String additional;
151         private String runtimeBeanYangName;
152
153         PatternGroupResolver(String key1, String value1, String value2, String additional) {
154             this.key1 = Preconditions.checkNotNull(key1);
155             this.value1 = Preconditions.checkNotNull(value1);
156             this.value2 = Preconditions.checkNotNull(value2);
157             this.additional = Preconditions.checkNotNull(additional);
158         }
159
160         String getModuleName() {
161             return key1.contains(XmlMappingConstants.TYPE_KEY) ? value1 : value2;
162         }
163
164         String getInstanceName() {
165             return key1.contains(XmlMappingConstants.NAME_KEY) ? value1 : value2;
166         }
167
168         Map<String, String> getAdditionalKeys(String elementName, String moduleName) {
169             HashMap<String, String> additionalAttributes = Maps.newHashMap();
170
171             runtimeBeanYangName = moduleName;
172             for (String additionalKeyValue : additional.split("/")) {
173                 if (Strings.isNullOrEmpty(additionalKeyValue)) {
174                     continue;
175                 }
176                 Matcher matcher = ADDITIONAL_PATTERN.matcher(additionalKeyValue);
177                 Preconditions.checkState(matcher.matches(),
178                         "Attribute %s not in required form on rpc element %s,"
179                                 + " required format for additional attributes is: %s",
180                         additionalKeyValue, elementName, ADDITIONAL_PATTERN_BLUEPRINT);
181                 String name = matcher.group("additionalKey");
182                 runtimeBeanYangName = name;
183                 additionalAttributes.put(name, matcher.group("additionalValue"));
184             }
185             return additionalAttributes;
186         }
187
188         private String getRuntimeBeanYangName() {
189             Preconditions.checkState(runtimeBeanYangName != null);
190             return runtimeBeanYangName;
191         }
192     }
193 }