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