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 static com.google.common.base.Preconditions.checkState;
12 import static java.lang.String.format;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.Date;
17 import java.util.HashMap;
18 import java.util.List;
20 import java.util.Map.Entry;
23 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.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.w3c.dom.Document;
35 import org.w3c.dom.Element;
37 import com.google.common.base.Optional;
38 import com.google.common.base.Preconditions;
39 import com.google.common.collect.HashMultimap;
40 import com.google.common.collect.Lists;
41 import com.google.common.collect.Maps;
42 import com.google.common.collect.Multimap;
45 private final Logger logger = LoggerFactory.getLogger(Config.class);
47 private final Map<String/* Namespace from yang file */,
48 Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
49 private final Map<String, ModuleConfig> moduleNamesToConfigs;
51 private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
53 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
54 this(moduleConfigs, Collections.<String, Map<Date, EditConfig.IdentityMapping>>emptyMap());
57 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
58 this.moduleConfigs = moduleConfigs;
59 Map<String, ModuleConfig> moduleNamesToConfigs = new HashMap<>();
60 for (Entry<String, Map<String, ModuleConfig>> entry : moduleConfigs.entrySet()) {
61 moduleNamesToConfigs.putAll(entry.getValue());
63 this.moduleNamesToConfigs = Collections.unmodifiableMap(moduleNamesToConfigs);
64 this.identityMap = identityMap;
67 public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
68 Map<String, Map<String, ModuleConfig>> configs) {
69 Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
71 Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
73 for (String namespace : configs.keySet()) {
75 Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
77 for (Entry<String, ModuleConfig> mbeEntry : configs.get(namespace).entrySet()) {
79 String moduleName = mbeEntry.getKey();
80 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
82 // TODO, this code does not support same module names from different namespaces
83 // Namespace should be present in ObjectName
85 if (instances == null)
88 innerRetVal.put(moduleName, instances);
92 retVal.put(namespace, innerRetVal);
97 private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
98 Multimap<String, ObjectName> retVal = HashMultimap.create();
100 for (ObjectName objectName : instancesToMap) {
101 String factoryName = ObjectNameUtil.getFactoryName(objectName);
102 retVal.put(factoryName, objectName);
107 // public Element toXml(Set<ObjectName> instancesToMap, String namespace,
108 // Document document) {
109 // return toXml(instancesToMap, Optional.of(namespace), document);
112 public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
113 Element dataElement, ServiceRegistryWrapper serviceTracker) {
115 Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
118 Element root = dataElement;
119 if (maybeNamespace.isPresent()) {
120 root.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
123 Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
124 root.appendChild(modulesElement);
125 for (String moduleNamespace : moduleToInstances.keySet()) {
126 for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstances.get(moduleNamespace)
129 ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
131 if (moduleMappingEntry.getValue().isEmpty()) {
135 for (ObjectName objectName : moduleMappingEntry.getValue()) {
136 modulesElement.appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
142 root.appendChild(Services.toXml(serviceTracker, document));
147 // TODO refactor, replace string representing namespace with namespace class
148 // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
151 public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(XmlElement xml, EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
152 Optional<XmlElement> modulesElement = getModulesElement(xml);
153 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
155 Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
157 for (XmlElement moduleElement : moduleElements) {
158 ResolvingStrategy<ModuleElementResolved> resolvingStrategy = new ResolvingStrategy<ModuleElementResolved>() {
160 public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException {
161 return moduleMapping.fromXml(moduleElement, serviceTracker,
162 instanceName, moduleNamespace, defaultStrategy, identityMap);
166 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
172 * return a map containing namespace -> moduleName -> instanceName map. Attribute parsing is omitted.
174 public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(XmlElement xml,
175 EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
176 Optional<XmlElement> modulesElement = getModulesElement(xml);
177 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
179 Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
181 for (XmlElement moduleElement : moduleElements) {
182 ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = new ResolvingStrategy<ModuleElementDefinition>() {
184 public ModuleElementDefinition resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
185 ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
186 EditStrategyType defaultStrategy) {
187 // TODO: add check for conflicts between global and local
189 String perInstanceEditStrategy = moduleElement.getAttribute(XmlNetconfConstants.OPERATION_ATTR_KEY,
190 XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
191 return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
195 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
200 private static Optional<XmlElement> getModulesElement(XmlElement xml) {
201 return xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
202 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
205 private List<XmlElement> getModulesElementList(Optional<XmlElement> modulesElement) throws NetconfDocumentedException {
206 List<XmlElement> moduleElements;
208 if (modulesElement.isPresent()) {
209 moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
210 modulesElement.get().checkUnrecognisedElements(moduleElements);
212 moduleElements = Lists.newArrayList();
214 return moduleElements;
217 private <T> void resolveModule(Map<String, Multimap<String, T>> retVal, ServiceRegistryWrapper serviceTracker,
218 XmlElement moduleElement, EditStrategyType defaultStrategy, ResolvingStrategy<T> resolvingStrategy) throws NetconfDocumentedException {
219 XmlElement typeElement = null;
220 typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
221 Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
222 String moduleNamespace = prefixToNamespace.getValue();
223 XmlElement nameElement = null;
224 nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
225 String instanceName = nameElement.getTextContent();
226 String factoryNameWithPrefix = typeElement.getTextContent();
227 String prefixOrEmptyString = prefixToNamespace.getKey();
228 String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
230 ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
232 Multimap<String, T> innerMap = retVal.get(moduleNamespace);
233 if (innerMap == null) {
234 innerMap = HashMultimap.create();
235 retVal.put(moduleNamespace, innerMap);
238 T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
239 instanceName, moduleNamespace, defaultStrategy);
241 innerMap.put(factoryName, resolvedElement);
244 public Services fromXmlServices(XmlElement xml) throws NetconfDocumentedException {
245 Optional<XmlElement> servicesElement = getServicesElement(xml);
248 if (servicesElement.isPresent()) {
249 services = Services.fromXml(servicesElement.get());
251 services = new Services();
257 private static Optional<XmlElement> getServicesElement(XmlElement xml) {
258 return xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
259 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
262 public static void checkUnrecognisedChildren(XmlElement parent) throws NetconfDocumentedException {
263 Optional<XmlElement> servicesOpt = getServicesElement(parent);
264 Optional<XmlElement> modulesOpt = getModulesElement(parent);
266 List<XmlElement> recognised = Lists.newArrayList();
267 if(servicesOpt.isPresent())
268 recognised.add(servicesOpt.get());
269 if(modulesOpt.isPresent())
270 recognised.add(modulesOpt.get());
272 parent.checkUnrecognisedElements(recognised);
275 private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
277 factoryNameWithPrefix.startsWith(prefixOrEmptyString),
278 format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
279 factoryNameWithPrefix, prefixOrEmptyString));
281 int factoryNameAfterPrefixIndex;
282 if (prefixOrEmptyString.isEmpty()) {
283 factoryNameAfterPrefixIndex = 0;
285 factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
287 return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
290 private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
291 Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
293 Preconditions.checkNotNull(mappingsFromNamespace,
294 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
295 instanceName, factoryName, moduleConfigs.keySet());
297 ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
298 checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
299 return moduleMapping;
302 private interface ResolvingStrategy<T> {
303 public T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
304 String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException;