2 * Copyright (c) 2015, 2017 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.config.facade.xml.mapping.config;
11 import static com.google.common.base.Preconditions.checkState;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.HashMultimap;
16 import com.google.common.collect.Lists;
17 import com.google.common.collect.Maps;
18 import com.google.common.collect.Multimap;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Date;
22 import java.util.List;
24 import java.util.Map.Entry;
26 import javax.management.ObjectName;
27 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
28 import org.opendaylight.controller.config.facade.xml.mapping.IdentityMapping;
29 import org.opendaylight.controller.config.facade.xml.osgi.EnumResolver;
30 import org.opendaylight.controller.config.facade.xml.strategy.EditStrategyType;
31 import org.opendaylight.controller.config.util.xml.DocumentedException;
32 import org.opendaylight.controller.config.util.xml.XmlElement;
33 import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
34 import org.opendaylight.controller.config.util.xml.XmlUtil;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
40 private final Map<String/* Namespace from yang file */,
41 Map<String /* Name of module entry from yang file */,
42 ModuleConfig>> moduleConfigs;
44 private final Map<String, Map<Date, IdentityMapping>> identityMap;
46 private final EnumResolver enumResolver;
48 public Config(final Map<String, Map<String, ModuleConfig>> moduleConfigs, final EnumResolver enumResolver) {
49 this(moduleConfigs, Collections.<String, Map<Date, IdentityMapping>>emptyMap(), enumResolver);
52 public Config(final Map<String, Map<String, ModuleConfig>> moduleConfigs,
53 final Map<String, Map<Date, IdentityMapping>> identityMap, final EnumResolver enumResolver) {
54 this.moduleConfigs = moduleConfigs;
55 this.identityMap = identityMap;
56 this.enumResolver = enumResolver;
59 public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(
60 final Set<ObjectName> instancesToMap, final Map<String, Map<String, ModuleConfig>> configs) {
61 Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
63 Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
65 for (Entry<String, Map<String, ModuleConfig>> namespaceToModuleToConfigEntry : configs.entrySet()) {
67 Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
69 for (Entry<String, ModuleConfig> mbeEntry : namespaceToModuleToConfigEntry.getValue().entrySet()) {
71 String moduleName = mbeEntry.getKey();
72 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
74 // TODO, this code does not support same module names from different namespaces
75 // Namespace should be present in ObjectName
77 if (instances == null) {
81 innerRetVal.put(moduleName, instances);
84 retVal.put(namespaceToModuleToConfigEntry.getKey(), innerRetVal);
89 private static Multimap<String, ObjectName> mapInstancesToModules(final Set<ObjectName> instancesToMap) {
90 Multimap<String, ObjectName> retVal = HashMultimap.create();
92 for (ObjectName objectName : instancesToMap) {
93 String factoryName = ObjectNameUtil.getFactoryName(objectName);
94 retVal.put(factoryName, objectName);
99 public Element toXml(final Set<ObjectName> instancesToMap, final Optional<String> maybeNamespace,
100 final Document document, final Element dataElement, final ServiceRegistryWrapper serviceTracker) {
102 Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
105 if (maybeNamespace.isPresent()) {
106 dataElement.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
109 Element modulesElement = XmlUtil.createElement(document, XmlMappingConstants.MODULES_KEY,
110 Optional.of(XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
111 dataElement.appendChild(modulesElement);
112 for (Entry<String, Map<String, Collection<ObjectName>>> moduleToInstanceEntry : moduleToInstances.entrySet()) {
113 for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstanceEntry.getValue()
116 ModuleConfig mapping = moduleConfigs.get(moduleToInstanceEntry.getKey())
117 .get(moduleMappingEntry.getKey());
119 if (moduleMappingEntry.getValue().isEmpty()) {
123 for (ObjectName objectName : moduleMappingEntry.getValue()) {
124 modulesElement.appendChild(
125 mapping.toXml(objectName, document, moduleToInstanceEntry.getKey(), enumResolver));
131 dataElement.appendChild(Services.toXml(serviceTracker, document));
136 public Element moduleToXml(final String moduleNamespace, final String factoryName, final String instanceName,
137 final ObjectName instanceON, final Document document) {
138 ModuleConfig moduleConfig = getModuleMapping(moduleNamespace, instanceName, factoryName);
139 return moduleConfig.toXml(instanceON, document, moduleNamespace, enumResolver);
142 // TODO refactor, replace string representing namespace with namespace class
143 // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
146 public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(final XmlElement xml,
147 final EditStrategyType defaultEditStrategyType, final ServiceRegistryWrapper serviceTracker)
148 throws DocumentedException {
149 Optional<XmlElement> modulesElement = getModulesElement(xml);
150 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
152 Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
154 ResolvingStrategy<ModuleElementResolved> resolvingStrategy = (moduleMapping, moduleElement, serviceTracker1,
155 instanceName, moduleNamespace, defaultStrategy) -> moduleMapping.fromXml(moduleElement, serviceTracker1,
156 instanceName, moduleNamespace, defaultStrategy, identityMap, enumResolver);
158 for (XmlElement moduleElement : moduleElements) {
159 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
166 * return a map containing namespace -> moduleName -> instanceName map.
167 * Attribute parsing is omitted.
169 public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(final XmlElement xml,
170 final EditStrategyType defaultEditStrategyType, final ServiceRegistryWrapper serviceTracker)
171 throws DocumentedException {
172 Optional<XmlElement> modulesElement = getModulesElement(xml);
173 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
175 Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
177 ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = (moduleMapping, moduleElement, serviceTracker1,
178 instanceName, moduleNamespace, defaultStrategy) -> {
179 // TODO: add check for conflicts between global and local edit
181 String perInstanceEditStrategy = moduleElement.getAttribute(XmlMappingConstants.OPERATION_ATTR_KEY,
182 XmlMappingConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
183 return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
186 for (XmlElement moduleElement : moduleElements) {
187 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
193 private static Optional<XmlElement> getModulesElement(final XmlElement xml) {
194 return xml.getOnlyChildElementOptionally(XmlMappingConstants.MODULES_KEY,
195 XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
198 private List<XmlElement> getModulesElementList(final Optional<XmlElement> modulesElement)
199 throws DocumentedException {
200 List<XmlElement> moduleElements;
202 if (modulesElement.isPresent()) {
203 moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlMappingConstants.MODULE_KEY);
204 modulesElement.get().checkUnrecognisedElements(moduleElements);
206 moduleElements = Lists.newArrayList();
208 return moduleElements;
211 private <T> void resolveModule(final Map<String, Multimap<String, T>> retVal,
212 final ServiceRegistryWrapper serviceTracker, final XmlElement moduleElement,
213 final EditStrategyType defaultStrategy, final ResolvingStrategy<T> resolvingStrategy)
214 throws DocumentedException {
215 XmlElement typeElement = null;
216 typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlMappingConstants.TYPE_KEY);
217 Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
218 String moduleNamespace = prefixToNamespace.getValue();
219 XmlElement nameElement = null;
220 nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlMappingConstants.NAME_KEY);
221 String instanceName = nameElement.getTextContent();
222 String factoryNameWithPrefix = typeElement.getTextContent();
223 String prefixOrEmptyString = prefixToNamespace.getKey();
224 String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
226 ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
228 Multimap<String, T> innerMap = retVal.computeIfAbsent(moduleNamespace, k -> HashMultimap.create());
230 T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker, instanceName,
231 moduleNamespace, defaultStrategy);
233 innerMap.put(factoryName, resolvedElement);
236 public Services fromXmlServices(final XmlElement xml) throws DocumentedException {
237 Optional<XmlElement> servicesElement = getServicesElement(xml);
240 if (servicesElement.isPresent()) {
241 services = Services.fromXml(servicesElement.get());
243 services = new Services();
249 private static Optional<XmlElement> getServicesElement(final XmlElement xml) {
250 return xml.getOnlyChildElementOptionally(XmlMappingConstants.SERVICES_KEY,
251 XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
254 public static void checkUnrecognisedChildren(final XmlElement parent) throws DocumentedException {
255 Optional<XmlElement> servicesOpt = getServicesElement(parent);
256 Optional<XmlElement> modulesOpt = getModulesElement(parent);
258 List<XmlElement> recognised = Lists.newArrayList();
259 if (servicesOpt.isPresent()) {
260 recognised.add(servicesOpt.get());
262 if (modulesOpt.isPresent()) {
263 recognised.add(modulesOpt.get());
266 parent.checkUnrecognisedElements(recognised);
269 private String getFactoryName(final String factoryNameWithPrefix, final String prefixOrEmptyString) {
270 checkState(factoryNameWithPrefix.startsWith(prefixOrEmptyString),
271 String.format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
272 factoryNameWithPrefix, prefixOrEmptyString));
274 int factoryNameAfterPrefixIndex;
275 if (prefixOrEmptyString.isEmpty()) {
276 factoryNameAfterPrefixIndex = 0;
278 factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
280 return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
283 private ModuleConfig getModuleMapping(final String moduleNamespace, final String instanceName,
284 final String factoryName) {
285 Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
287 Preconditions.checkNotNull(mappingsFromNamespace,
288 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
289 instanceName, factoryName, moduleConfigs.keySet());
291 ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
292 checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
293 return moduleMapping;
296 private interface ResolvingStrategy<T> {
297 T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
298 String instanceName, String moduleNamespace, EditStrategyType defaultStrategy)
299 throws DocumentedException;