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 org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
18 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
19 import org.opendaylight.controller.netconf.util.xml.XmlElement;
20 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
21 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import org.w3c.dom.Document;
25 import org.w3c.dom.Element;
27 import javax.management.ObjectName;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.List;
33 import java.util.Map.Entry;
36 import static com.google.common.base.Preconditions.checkState;
37 import static java.lang.String.format;
40 private final Logger logger = LoggerFactory.getLogger(Config.class);
42 private final Map<String/* Namespace from yang file */,
43 Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
44 private final Map<String, ModuleConfig> moduleNamesToConfigs;
46 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
47 this.moduleConfigs = moduleConfigs;
48 Map<String, ModuleConfig> moduleNamesToConfigs = new HashMap<>();
49 for (Entry<String, Map<String, ModuleConfig>> entry : moduleConfigs.entrySet()) {
50 moduleNamesToConfigs.putAll(entry.getValue());
52 this.moduleNamesToConfigs = Collections.unmodifiableMap(moduleNamesToConfigs);
55 public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
56 Map<String, Map<String, ModuleConfig>> configs) {
57 Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
59 Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
61 for (String namespace : configs.keySet()) {
63 Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
65 for (Entry<String, ModuleConfig> mbeEntry : configs.get(namespace).entrySet()) {
67 String moduleName = mbeEntry.getKey();
68 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
70 // TODO, this code does not support same module names from different namespaces
71 // Namespace should be present in ObjectName
73 if (instances == null)
76 innerRetVal.put(moduleName, instances);
80 retVal.put(namespace, innerRetVal);
85 private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
86 Multimap<String, ObjectName> retVal = HashMultimap.create();
88 for (ObjectName objectName : instancesToMap) {
89 String factoryName = ObjectNameUtil.getFactoryName(objectName);
90 retVal.put(factoryName, objectName);
95 // public Element toXml(Set<ObjectName> instancesToMap, String namespace,
96 // Document document) {
97 // return toXml(instancesToMap, Optional.of(namespace), document);
100 public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
101 Element dataElement, ServiceRegistryWrapper serviceTracker) {
103 Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
106 Element root = dataElement;
107 if (maybeNamespace.isPresent()) {
108 XmlUtil.addNamespaceAttr(root, maybeNamespace.get());
111 Element modulesElement = document.createElement(XmlNetconfConstants.MODULES_KEY);
112 XmlUtil.addNamespaceAttr(modulesElement,
113 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
114 root.appendChild(modulesElement);
115 for (String moduleNamespace : moduleToInstances.keySet()) {
116 for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstances.get(moduleNamespace)
119 ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
121 if (moduleMappingEntry.getValue().isEmpty()) {
122 addEmptyModulesCommented(document, modulesElement, moduleNamespace, moduleMappingEntry);
124 for (ObjectName objectName : moduleMappingEntry.getValue()) {
126 .appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
133 root.appendChild(Services.toXml(serviceTracker, document));
138 // TODO remove commented modules from output
139 private void addEmptyModulesCommented(Document document, Element root, String moduleNamespace,
140 Entry<String, Collection<ObjectName>> moduleMappingEntry) {
141 Element emptyModule = document.createElement(XmlNetconfConstants.MODULE_KEY);
143 Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY,
144 moduleMappingEntry.getKey());
145 emptyModule.appendChild(typeElement);
147 root.appendChild(document.createComment(XmlUtil.toString(emptyModule, false)));
150 // TODO refactor, replace string representing namespace with namespace class
151 // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
154 public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(XmlElement xml, EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) {
155 Optional<XmlElement> modulesElement = getModulesElement(xml);
156 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
158 Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
160 for (XmlElement moduleElement : moduleElements) {
161 ResolvingStrategy<ModuleElementResolved> resolvingStrategy = new ResolvingStrategy<ModuleElementResolved>() {
163 public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) {
164 return moduleMapping.fromXml(moduleElement, serviceTracker,
165 instanceName, moduleNamespace, defaultStrategy);
169 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
175 * return a map containing namespace -> moduleName -> instanceName map. Attribute parsing is omitted.
177 public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(XmlElement xml,
178 EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) {
179 Optional<XmlElement> modulesElement = getModulesElement(xml);
180 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
182 Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
184 for (XmlElement moduleElement : moduleElements) {
185 ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = new ResolvingStrategy<ModuleElementDefinition>() {
187 public ModuleElementDefinition resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
188 ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
189 EditStrategyType defaultStrategy) {
190 // TODO: add check for conflicts between global and local
192 String perInstanceEditStrategy = moduleElement.getAttribute(XmlNetconfConstants.OPERATION_ATTR_KEY,
193 XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
194 return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
198 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
203 private static Optional<XmlElement> getModulesElement(XmlElement xml) {
204 return xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
205 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
208 private List<XmlElement> getModulesElementList(Optional<XmlElement> modulesElement) {
209 List<XmlElement> moduleElements;
211 if (modulesElement.isPresent()) {
212 moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
213 modulesElement.get().checkUnrecognisedElements(moduleElements);
215 moduleElements = Lists.newArrayList();
217 return moduleElements;
220 private <T> void resolveModule(Map<String, Multimap<String, T>> retVal, ServiceRegistryWrapper serviceTracker,
221 XmlElement moduleElement, EditStrategyType defaultStrategy, ResolvingStrategy<T> resolvingStrategy) {
222 XmlElement typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
223 Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
224 String moduleNamespace = prefixToNamespace.getValue();
225 XmlElement nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
226 String instanceName = nameElement.getTextContent();
227 String factoryNameWithPrefix = typeElement.getTextContent();
228 String prefixOrEmptyString = prefixToNamespace.getKey();
229 String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
231 ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
233 Multimap<String, T> innerMap = retVal.get(moduleNamespace);
234 if (innerMap == null) {
235 innerMap = HashMultimap.create();
236 retVal.put(moduleNamespace, innerMap);
239 T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
240 instanceName, moduleNamespace, defaultStrategy);
242 innerMap.put(factoryName, resolvedElement);
245 public Services fromXmlServices(XmlElement xml) {
246 Optional<XmlElement> servicesElement = getServicesElement(xml);
249 if (servicesElement.isPresent()) {
250 services = Services.fromXml(servicesElement.get());
252 services = new Services();
258 private static Optional<XmlElement> getServicesElement(XmlElement xml) {
259 return xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
260 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
263 public static void checkUnrecognisedChildren(XmlElement parent) {
264 Optional<XmlElement> servicesOpt = getServicesElement(parent);
265 Optional<XmlElement> modulesOpt = getModulesElement(parent);
267 List<XmlElement> recognised = Lists.newArrayList();
268 if(servicesOpt.isPresent())
269 recognised.add(servicesOpt.get());
270 if(modulesOpt.isPresent())
271 recognised.add(modulesOpt.get());
273 parent.checkUnrecognisedElements(recognised);
276 private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
278 factoryNameWithPrefix.startsWith(prefixOrEmptyString),
279 format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
280 factoryNameWithPrefix, prefixOrEmptyString));
282 int factoryNameAfterPrefixIndex;
283 if (prefixOrEmptyString.isEmpty()) {
284 factoryNameAfterPrefixIndex = 0;
286 factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
288 return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
291 private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
292 Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
294 Preconditions.checkNotNull(mappingsFromNamespace,
295 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
296 instanceName, factoryName, moduleConfigs.keySet());
298 ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
299 checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
300 return moduleMapping;
303 private interface ResolvingStrategy<T> {
304 public T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
305 String instanceName, String moduleNamespace, EditStrategyType defaultStrategy);