2 * Copyright (c) 2015 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;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.HashMultimap;
15 import com.google.common.collect.Lists;
16 import com.google.common.collect.Maps;
17 import com.google.common.collect.Multimap;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.Date;
21 import java.util.List;
23 import java.util.Map.Entry;
25 import javax.management.ObjectName;
26 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
27 import org.opendaylight.controller.config.facade.xml.mapping.IdentityMapping;
28 import org.opendaylight.controller.config.facade.xml.osgi.EnumResolver;
29 import org.opendaylight.controller.config.facade.xml.strategy.EditStrategyType;
30 import org.opendaylight.controller.config.util.xml.DocumentedException;
31 import org.opendaylight.controller.config.util.xml.XmlElement;
32 import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
33 import org.opendaylight.controller.config.util.xml.XmlUtil;
34 import org.w3c.dom.Document;
35 import org.w3c.dom.Element;
40 private final Map<String/* Namespace from yang file */,
41 Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
43 private final Map<String, Map<Date, IdentityMapping>> identityMap;
45 private final EnumResolver enumResolver;
47 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, final EnumResolver enumResolver) {
48 this(moduleConfigs, Collections.<String, Map<Date, IdentityMapping>>emptyMap(), enumResolver);
51 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date, IdentityMapping>> identityMap, final EnumResolver enumResolver) {
52 this.moduleConfigs = moduleConfigs;
53 this.identityMap = identityMap;
54 this.enumResolver = enumResolver;
57 public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
58 Map<String, Map<String, ModuleConfig>> configs) {
59 Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
61 Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
63 for (Entry<String, Map<String, ModuleConfig>> namespaceToModuleToConfigEntry : configs.entrySet()) {
65 Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
67 for (Entry<String, ModuleConfig> mbeEntry : namespaceToModuleToConfigEntry.getValue().entrySet()) {
69 String moduleName = mbeEntry.getKey();
70 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
72 // TODO, this code does not support same module names from different namespaces
73 // Namespace should be present in ObjectName
75 if (instances == null){
79 innerRetVal.put(moduleName, instances);
83 retVal.put(namespaceToModuleToConfigEntry.getKey(), innerRetVal);
88 private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
89 Multimap<String, ObjectName> retVal = HashMultimap.create();
91 for (ObjectName objectName : instancesToMap) {
92 String factoryName = ObjectNameUtil.getFactoryName(objectName);
93 retVal.put(factoryName, objectName);
98 public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
99 Element dataElement, ServiceRegistryWrapper serviceTracker) {
101 Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
104 if (maybeNamespace.isPresent()) {
105 dataElement.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
108 Element modulesElement = XmlUtil.createElement(document, XmlMappingConstants.MODULES_KEY, Optional.of(XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
109 dataElement.appendChild(modulesElement);
110 for (Entry<String, Map<String, Collection<ObjectName>>> moduleToInstanceEntry : moduleToInstances.entrySet()) {
111 for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstanceEntry.getValue()
114 ModuleConfig mapping = moduleConfigs.get(moduleToInstanceEntry.getKey()).get(moduleMappingEntry.getKey());
116 if (moduleMappingEntry.getValue().isEmpty()) {
120 for (ObjectName objectName : moduleMappingEntry.getValue()) {
121 modulesElement.appendChild(mapping.toXml(objectName, document, moduleToInstanceEntry.getKey(), enumResolver));
127 dataElement.appendChild(Services.toXml(serviceTracker, document));
132 public Element moduleToXml(String moduleNamespace, String factoryName, String instanceName,
133 ObjectName instanceON, Document document) {
134 ModuleConfig moduleConfig = getModuleMapping(moduleNamespace, instanceName, factoryName);
135 return moduleConfig.toXml(instanceON, document, moduleNamespace, enumResolver);
138 // TODO refactor, replace string representing namespace with namespace class
139 // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
142 public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(XmlElement xml, EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws DocumentedException {
143 Optional<XmlElement> modulesElement = getModulesElement(xml);
144 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
146 Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
148 for (XmlElement moduleElement : moduleElements) {
149 ResolvingStrategy<ModuleElementResolved> resolvingStrategy = new ResolvingStrategy<ModuleElementResolved>() {
151 public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws DocumentedException {
152 return moduleMapping.fromXml(moduleElement, serviceTracker,
153 instanceName, moduleNamespace, defaultStrategy, identityMap, enumResolver);
157 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
163 * return a map containing namespace -> moduleName -> instanceName map. Attribute parsing is omitted.
165 public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(XmlElement xml,
166 EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws DocumentedException {
167 Optional<XmlElement> modulesElement = getModulesElement(xml);
168 List<XmlElement> moduleElements = getModulesElementList(modulesElement);
170 Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
172 for (XmlElement moduleElement : moduleElements) {
173 ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = new ResolvingStrategy<ModuleElementDefinition>() {
175 public ModuleElementDefinition resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
176 ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
177 EditStrategyType defaultStrategy) {
178 // TODO: add check for conflicts between global and local
180 String perInstanceEditStrategy = moduleElement.getAttribute(XmlMappingConstants.OPERATION_ATTR_KEY,
181 XmlMappingConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
182 return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
186 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
191 private static Optional<XmlElement> getModulesElement(XmlElement xml) {
192 return xml.getOnlyChildElementOptionally(XmlMappingConstants.MODULES_KEY,
193 XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
196 private List<XmlElement> getModulesElementList(Optional<XmlElement> modulesElement) throws DocumentedException {
197 List<XmlElement> moduleElements;
199 if (modulesElement.isPresent()) {
200 moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlMappingConstants.MODULE_KEY);
201 modulesElement.get().checkUnrecognisedElements(moduleElements);
203 moduleElements = Lists.newArrayList();
205 return moduleElements;
208 private <T> void resolveModule(Map<String, Multimap<String, T>> retVal, ServiceRegistryWrapper serviceTracker,
209 XmlElement moduleElement, EditStrategyType defaultStrategy, ResolvingStrategy<T> resolvingStrategy) throws DocumentedException {
210 XmlElement typeElement = null;
211 typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlMappingConstants.TYPE_KEY);
212 Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
213 String moduleNamespace = prefixToNamespace.getValue();
214 XmlElement nameElement = null;
215 nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlMappingConstants.NAME_KEY);
216 String instanceName = nameElement.getTextContent();
217 String factoryNameWithPrefix = typeElement.getTextContent();
218 String prefixOrEmptyString = prefixToNamespace.getKey();
219 String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
221 ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
223 Multimap<String, T> innerMap = retVal.get(moduleNamespace);
224 if (innerMap == null) {
225 innerMap = HashMultimap.create();
226 retVal.put(moduleNamespace, innerMap);
229 T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
230 instanceName, moduleNamespace, defaultStrategy);
232 innerMap.put(factoryName, resolvedElement);
235 public Services fromXmlServices(XmlElement xml) throws DocumentedException {
236 Optional<XmlElement> servicesElement = getServicesElement(xml);
239 if (servicesElement.isPresent()) {
240 services = Services.fromXml(servicesElement.get());
242 services = new Services();
248 private static Optional<XmlElement> getServicesElement(XmlElement xml) {
249 return xml.getOnlyChildElementOptionally(XmlMappingConstants.SERVICES_KEY,
250 XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
253 public static void checkUnrecognisedChildren(XmlElement parent) throws DocumentedException {
254 Optional<XmlElement> servicesOpt = getServicesElement(parent);
255 Optional<XmlElement> modulesOpt = getModulesElement(parent);
257 List<XmlElement> recognised = Lists.newArrayList();
258 if(servicesOpt.isPresent()){
259 recognised.add(servicesOpt.get());
261 if(modulesOpt.isPresent()){
262 recognised.add(modulesOpt.get());
265 parent.checkUnrecognisedElements(recognised);
268 private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
270 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(String moduleNamespace, String instanceName, String factoryName) {
284 Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
286 Preconditions.checkNotNull(mappingsFromNamespace,
287 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
288 instanceName, factoryName, moduleConfigs.keySet());
290 ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
291 checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
292 return moduleMapping;
295 private interface ResolvingStrategy<T> {
296 T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
297 String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws DocumentedException;