2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.HashMultimap;
14 import com.google.common.collect.Lists;
15 import com.google.common.collect.Maps;
16 import com.google.common.collect.Multimap;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.List;
22 import java.util.Map.Entry;
24 import javax.management.ObjectName;
25 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
26 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
27 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
28 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
29 import org.opendaylight.controller.netconf.util.xml.XmlElement;
30 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
31 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Element;
34 import static com.google.common.base.Preconditions.checkState;
39 private final Map<String/* Namespace from yang file */,
40 Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
42 private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
44 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
45 this(moduleConfigs, Collections.<String, Map<Date, EditConfig.IdentityMapping>>emptyMap());
48 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
49 this.moduleConfigs = moduleConfigs;
50 this.identityMap = identityMap;
53 public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
54 Map<String, Map<String, ModuleConfig>> configs) {
55 Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
57 Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
59 for (String namespace : configs.keySet()) {
61 Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
63 for (Entry<String, ModuleConfig> mbeEntry : configs.get(namespace).entrySet()) {
65 String moduleName = mbeEntry.getKey();
66 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
68 // TODO, this code does not support same module names from different namespaces
69 // Namespace should be present in ObjectName
71 if (instances == null){
75 innerRetVal.put(moduleName, instances);
79 retVal.put(namespace, innerRetVal);
84 private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
85 Multimap<String, ObjectName> retVal = HashMultimap.create();
87 for (ObjectName objectName : instancesToMap) {
88 String factoryName = ObjectNameUtil.getFactoryName(objectName);
89 retVal.put(factoryName, objectName);
94 public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
95 Element dataElement, ServiceRegistryWrapper serviceTracker) {
97 Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
100 Element root = dataElement;
101 if (maybeNamespace.isPresent()) {
102 root.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
105 Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
106 root.appendChild(modulesElement);
107 for (String moduleNamespace : moduleToInstances.keySet()) {
108 for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstances.get(moduleNamespace)
111 ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
113 if (moduleMappingEntry.getValue().isEmpty()) {
117 for (ObjectName objectName : moduleMappingEntry.getValue()) {
118 modulesElement.appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
124 root.appendChild(Services.toXml(serviceTracker, document));
129 // TODO refactor, replace string representing namespace with namespace class
130 // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
133 public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(XmlElement xml, EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
134 Optional<XmlElement> modulesElement = getModulesElement(xml);
135 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
137 Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
139 for (XmlElement moduleElement : moduleElements) {
140 ResolvingStrategy<ModuleElementResolved> resolvingStrategy = new ResolvingStrategy<ModuleElementResolved>() {
142 public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException {
143 return moduleMapping.fromXml(moduleElement, serviceTracker,
144 instanceName, moduleNamespace, defaultStrategy, identityMap);
148 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
154 * return a map containing namespace -> moduleName -> instanceName map. Attribute parsing is omitted.
156 public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(XmlElement xml,
157 EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
158 Optional<XmlElement> modulesElement = getModulesElement(xml);
159 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
161 Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
163 for (XmlElement moduleElement : moduleElements) {
164 ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = new ResolvingStrategy<ModuleElementDefinition>() {
166 public ModuleElementDefinition resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
167 ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
168 EditStrategyType defaultStrategy) {
169 // TODO: add check for conflicts between global and local
171 String perInstanceEditStrategy = moduleElement.getAttribute(XmlNetconfConstants.OPERATION_ATTR_KEY,
172 XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
173 return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
177 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
182 private static Optional<XmlElement> getModulesElement(XmlElement xml) {
183 return xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
184 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
187 private List<XmlElement> getModulesElementList(Optional<XmlElement> modulesElement) throws NetconfDocumentedException {
188 List<XmlElement> moduleElements;
190 if (modulesElement.isPresent()) {
191 moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
192 modulesElement.get().checkUnrecognisedElements(moduleElements);
194 moduleElements = Lists.newArrayList();
196 return moduleElements;
199 private <T> void resolveModule(Map<String, Multimap<String, T>> retVal, ServiceRegistryWrapper serviceTracker,
200 XmlElement moduleElement, EditStrategyType defaultStrategy, ResolvingStrategy<T> resolvingStrategy) throws NetconfDocumentedException {
201 XmlElement typeElement = null;
202 typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
203 Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
204 String moduleNamespace = prefixToNamespace.getValue();
205 XmlElement nameElement = null;
206 nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
207 String instanceName = nameElement.getTextContent();
208 String factoryNameWithPrefix = typeElement.getTextContent();
209 String prefixOrEmptyString = prefixToNamespace.getKey();
210 String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
212 ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
214 Multimap<String, T> innerMap = retVal.get(moduleNamespace);
215 if (innerMap == null) {
216 innerMap = HashMultimap.create();
217 retVal.put(moduleNamespace, innerMap);
220 T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
221 instanceName, moduleNamespace, defaultStrategy);
223 innerMap.put(factoryName, resolvedElement);
226 public Services fromXmlServices(XmlElement xml) throws NetconfDocumentedException {
227 Optional<XmlElement> servicesElement = getServicesElement(xml);
230 if (servicesElement.isPresent()) {
231 services = Services.fromXml(servicesElement.get());
233 services = new Services();
239 private static Optional<XmlElement> getServicesElement(XmlElement xml) {
240 return xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
241 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
244 public static void checkUnrecognisedChildren(XmlElement parent) throws NetconfDocumentedException {
245 Optional<XmlElement> servicesOpt = getServicesElement(parent);
246 Optional<XmlElement> modulesOpt = getModulesElement(parent);
248 List<XmlElement> recognised = Lists.newArrayList();
249 if(servicesOpt.isPresent()){
250 recognised.add(servicesOpt.get());
252 if(modulesOpt.isPresent()){
253 recognised.add(modulesOpt.get());
256 parent.checkUnrecognisedElements(recognised);
259 private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
261 factoryNameWithPrefix.startsWith(prefixOrEmptyString),
262 String.format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
263 factoryNameWithPrefix, prefixOrEmptyString));
265 int factoryNameAfterPrefixIndex;
266 if (prefixOrEmptyString.isEmpty()) {
267 factoryNameAfterPrefixIndex = 0;
269 factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
271 return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
274 private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
275 Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
277 Preconditions.checkNotNull(mappingsFromNamespace,
278 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
279 instanceName, factoryName, moduleConfigs.keySet());
281 ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
282 checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
283 return moduleMapping;
286 private interface ResolvingStrategy<T> {
287 public T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
288 String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException;