CDS: Add stress test RPC to the cars model
[controller.git] / opendaylight / config / config-manager-facade-xml / src / main / java / org / opendaylight / controller / config / facade / xml / mapping / config / Config.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.config.facade.xml.mapping.config;
10
11 import static com.google.common.base.Preconditions.checkState;
12
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;
23 import java.util.Map;
24 import java.util.Map.Entry;
25 import java.util.Set;
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;
37
38
39 public class Config {
40
41     private final Map<String/* Namespace from yang file */,
42             Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
43
44     private final Map<String, Map<Date, IdentityMapping>> identityMap;
45
46     private final EnumResolver enumResolver;
47
48     public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, final EnumResolver enumResolver) {
49         this(moduleConfigs, Collections.<String, Map<Date, IdentityMapping>>emptyMap(), enumResolver);
50     }
51
52     public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date, IdentityMapping>> identityMap, final EnumResolver enumResolver) {
53         this.moduleConfigs = moduleConfigs;
54         this.identityMap = identityMap;
55         this.enumResolver = enumResolver;
56     }
57
58     public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
59                                                                                 Map<String, Map<String, ModuleConfig>> configs) {
60         Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
61
62         Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
63
64         for (Entry<String, Map<String, ModuleConfig>> namespaceToModuleToConfigEntry : configs.entrySet()) {
65
66             Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
67
68             for (Entry<String, ModuleConfig> mbeEntry : namespaceToModuleToConfigEntry.getValue().entrySet()) {
69
70                 String moduleName = mbeEntry.getKey();
71                 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
72
73                 // TODO, this code does not support same module names from different namespaces
74                 // Namespace should be present in ObjectName
75
76                 if (instances == null){
77                     continue;
78                 }
79
80                 innerRetVal.put(moduleName, instances);
81
82             }
83
84             retVal.put(namespaceToModuleToConfigEntry.getKey(), innerRetVal);
85         }
86         return retVal;
87     }
88
89     private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
90         Multimap<String, ObjectName> retVal = HashMultimap.create();
91
92         for (ObjectName objectName : instancesToMap) {
93             String factoryName = ObjectNameUtil.getFactoryName(objectName);
94             retVal.put(factoryName, objectName);
95         }
96         return retVal;
97     }
98
99     public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
100             Element dataElement, ServiceRegistryWrapper serviceTracker) {
101
102         Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
103                 moduleConfigs);
104
105         if (maybeNamespace.isPresent()) {
106             dataElement.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
107         }
108
109         Element modulesElement = XmlUtil.createElement(document, XmlMappingConstants.MODULES_KEY, Optional.of(XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
110         dataElement.appendChild(modulesElement);
111         for (Entry<String, Map<String, Collection<ObjectName>>> moduleToInstanceEntry : moduleToInstances.entrySet()) {
112             for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstanceEntry.getValue()
113                     .entrySet()) {
114
115                 ModuleConfig mapping = moduleConfigs.get(moduleToInstanceEntry.getKey()).get(moduleMappingEntry.getKey());
116
117                 if (moduleMappingEntry.getValue().isEmpty()) {
118                     continue;
119                 }
120
121                 for (ObjectName objectName : moduleMappingEntry.getValue()) {
122                     modulesElement.appendChild(mapping.toXml(objectName, document, moduleToInstanceEntry.getKey(), enumResolver));
123                 }
124
125             }
126         }
127
128         dataElement.appendChild(Services.toXml(serviceTracker, document));
129
130         return dataElement;
131     }
132
133     // TODO refactor, replace string representing namespace with namespace class
134     // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
135     // class
136
137     public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(XmlElement xml, EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws DocumentedException {
138         Optional<XmlElement> modulesElement = getModulesElement(xml);
139         List<XmlElement> moduleElements = getModulesElementList(modulesElement);
140
141         Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
142
143         for (XmlElement moduleElement : moduleElements) {
144             ResolvingStrategy<ModuleElementResolved> resolvingStrategy = new ResolvingStrategy<ModuleElementResolved>() {
145                 @Override
146                 public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws DocumentedException {
147                     return moduleMapping.fromXml(moduleElement, serviceTracker,
148                             instanceName, moduleNamespace, defaultStrategy, identityMap, enumResolver);
149                 }
150             };
151
152             resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
153         }
154         return retVal;
155     }
156
157     /**
158      * return a map containing namespace -> moduleName -> instanceName map. Attribute parsing is omitted.
159      */
160     public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(XmlElement xml,
161             EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws DocumentedException {
162         Optional<XmlElement> modulesElement = getModulesElement(xml);
163         List<XmlElement> moduleElements = getModulesElementList(modulesElement);
164
165         Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
166
167         for (XmlElement moduleElement : moduleElements) {
168             ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = new ResolvingStrategy<ModuleElementDefinition>() {
169                 @Override
170                 public ModuleElementDefinition resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
171                         ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
172                         EditStrategyType defaultStrategy) {
173                     // TODO: add check for conflicts between global and local
174                     // edit strategy
175                     String perInstanceEditStrategy = moduleElement.getAttribute(XmlMappingConstants.OPERATION_ATTR_KEY,
176                             XmlMappingConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
177                     return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
178                 }
179             };
180
181             resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
182         }
183         return retVal;
184     }
185
186     private static Optional<XmlElement> getModulesElement(XmlElement xml) {
187         return xml.getOnlyChildElementOptionally(XmlMappingConstants.MODULES_KEY,
188                     XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
189     }
190
191     private List<XmlElement> getModulesElementList(Optional<XmlElement> modulesElement) throws DocumentedException {
192         List<XmlElement> moduleElements;
193
194         if (modulesElement.isPresent()) {
195             moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlMappingConstants.MODULE_KEY);
196             modulesElement.get().checkUnrecognisedElements(moduleElements);
197         } else {
198             moduleElements = Lists.newArrayList();
199         }
200         return moduleElements;
201     }
202
203     private <T> void resolveModule(Map<String, Multimap<String, T>> retVal, ServiceRegistryWrapper serviceTracker,
204             XmlElement moduleElement, EditStrategyType defaultStrategy, ResolvingStrategy<T> resolvingStrategy) throws DocumentedException {
205         XmlElement typeElement = null;
206         typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlMappingConstants.TYPE_KEY);
207         Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
208         String moduleNamespace = prefixToNamespace.getValue();
209         XmlElement nameElement = null;
210         nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlMappingConstants.NAME_KEY);
211         String instanceName = nameElement.getTextContent();
212         String factoryNameWithPrefix = typeElement.getTextContent();
213         String prefixOrEmptyString = prefixToNamespace.getKey();
214         String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
215
216         ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
217
218         Multimap<String, T> innerMap = retVal.get(moduleNamespace);
219         if (innerMap == null) {
220             innerMap = HashMultimap.create();
221             retVal.put(moduleNamespace, innerMap);
222         }
223
224         T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
225                 instanceName, moduleNamespace, defaultStrategy);
226
227         innerMap.put(factoryName, resolvedElement);
228     }
229
230     public Services fromXmlServices(XmlElement xml) throws DocumentedException {
231         Optional<XmlElement> servicesElement = getServicesElement(xml);
232
233         Services services;
234         if (servicesElement.isPresent()) {
235             services = Services.fromXml(servicesElement.get());
236         } else {
237             services = new Services();
238         }
239
240         return services;
241     }
242
243     private static Optional<XmlElement> getServicesElement(XmlElement xml) {
244         return xml.getOnlyChildElementOptionally(XmlMappingConstants.SERVICES_KEY,
245                     XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
246     }
247
248     public static void checkUnrecognisedChildren(XmlElement parent) throws DocumentedException {
249         Optional<XmlElement> servicesOpt = getServicesElement(parent);
250         Optional<XmlElement> modulesOpt = getModulesElement(parent);
251
252         List<XmlElement> recognised = Lists.newArrayList();
253         if(servicesOpt.isPresent()){
254             recognised.add(servicesOpt.get());
255         }
256         if(modulesOpt.isPresent()){
257             recognised.add(modulesOpt.get());
258         }
259
260         parent.checkUnrecognisedElements(recognised);
261     }
262
263     private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
264         checkState(
265                 factoryNameWithPrefix.startsWith(prefixOrEmptyString),
266                 String.format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
267                         factoryNameWithPrefix, prefixOrEmptyString));
268
269         int factoryNameAfterPrefixIndex;
270         if (prefixOrEmptyString.isEmpty()) {
271             factoryNameAfterPrefixIndex = 0;
272         } else {
273             factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
274         }
275         return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
276     }
277
278     private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
279         Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
280
281         Preconditions.checkNotNull(mappingsFromNamespace,
282                 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
283                 instanceName, factoryName, moduleConfigs.keySet());
284
285         ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
286         checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
287         return moduleMapping;
288     }
289
290     private interface ResolvingStrategy<T> {
291         public T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
292                                 String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws DocumentedException;
293     }
294 }