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 private Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
56 Services serviceTracker) {
57 Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
59 Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
61 for (String namespace : moduleConfigs.keySet()) {
63 Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
65 for (Entry<String, ModuleConfig> mbeEntry : moduleConfigs.get(namespace).entrySet()) {
67 String moduleName = mbeEntry.getKey();
68 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
70 if (instances == null)
73 innerRetVal.put(moduleName, instances);
75 // All found instances add to service tracker in advance
76 // This way all instances will be serialized as all available
77 // services when get-config is triggered
78 // (even if they are not used as services by other instances)
79 // = more user friendly
80 addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
84 retVal.put(namespace, innerRetVal);
89 private void addServices(Services serviceTracker, Collection<ObjectName> instances,
90 Multimap<String, String> providedServices) {
91 for (ObjectName instanceOn : instances) {
92 for (Entry<String, String> serviceName : providedServices.entries()) {
93 serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn);
98 private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
99 Multimap<String, ObjectName> retVal = HashMultimap.create();
101 for (ObjectName objectName : instancesToMap) {
102 String factoryName = ObjectNameUtil.getFactoryName(objectName);
103 retVal.put(factoryName, objectName);
108 // public Element toXml(Set<ObjectName> instancesToMap, String namespace,
109 // Document document) {
110 // return toXml(instancesToMap, Optional.of(namespace), document);
113 public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
114 Element dataElement) {
115 Services serviceTracker = new Services();
117 Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
120 Element root = dataElement;
121 if (maybeNamespace.isPresent()) {
122 XmlUtil.addNamespaceAttr(root, maybeNamespace.get());
125 Element modulesElement = document.createElement(XmlNetconfConstants.MODULES_KEY);
126 XmlUtil.addNamespaceAttr(modulesElement,
127 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
128 root.appendChild(modulesElement);
129 for (String moduleNamespace : moduleToInstances.keySet()) {
130 for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstances.get(moduleNamespace)
133 ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
135 if (moduleMappingEntry.getValue().isEmpty()) {
136 addEmptyModulesCommented(document, modulesElement, moduleNamespace, moduleMappingEntry);
138 for (ObjectName objectName : moduleMappingEntry.getValue()) {
140 .appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
147 root.appendChild(serviceTracker.toXml(serviceTracker.getMappedServices(), document));
152 // TODO remove commented modules from output
153 private void addEmptyModulesCommented(Document document, Element root, String moduleNamespace,
154 Entry<String, Collection<ObjectName>> moduleMappingEntry) {
155 Element emptyModule = document.createElement(XmlNetconfConstants.MODULE_KEY);
157 Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY,
158 moduleMappingEntry.getKey());
159 emptyModule.appendChild(typeElement);
161 root.appendChild(document.createComment(XmlUtil.toString(emptyModule, false)));
164 // TODO refactor, replace string representing namespace with namespace class
165 // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
167 public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml, Set<ObjectName> instancesForFillingServiceRefMapping,
168 EditStrategyType defaultEditStrategyType) {
169 Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
171 List<XmlElement> recognisedChildren = Lists.newArrayList();
173 Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping);
174 List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
176 xml.checkUnrecognisedElements(recognisedChildren);
178 for (XmlElement moduleElement : moduleElements) {
179 resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType);
185 private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
186 Optional<XmlElement> modulesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
187 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
188 List<XmlElement> moduleElements;
189 if (modulesElement.isPresent()) {
190 moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
191 recognisedChildren.add(modulesElement.get());
192 modulesElement.get().checkUnrecognisedElements(moduleElements);
194 moduleElements = Lists.newArrayList();
196 return moduleElements;
199 private void resolveModule(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker,
200 XmlElement moduleElement, EditStrategyType defaultStrategy) {
201 XmlElement typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
202 Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
203 String moduleNamespace = prefixToNamespace.getValue();
204 XmlElement nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
205 String instanceName = nameElement.getTextContent();
206 String factoryNameWithPrefix = typeElement.getTextContent();
207 String prefixOrEmptyString = prefixToNamespace.getKey();
208 String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
210 ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
212 Multimap<String, ModuleElementResolved> innerMap = retVal.get(moduleNamespace);
213 if (innerMap == null) {
214 innerMap = HashMultimap.create();
215 retVal.put(moduleNamespace, innerMap);
218 ModuleElementResolved moduleElementResolved = moduleMapping.fromXml(moduleElement, serviceTracker,
219 instanceName, moduleNamespace, defaultStrategy);
221 innerMap.put(factoryName, moduleElementResolved);
224 private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren, Set<ObjectName> instancesForFillingServiceRefMapping) {
225 Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
226 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
228 Map<String, Map<String, Map<String, String>>> mappedServices;
229 if (servicesElement.isPresent()) {
230 mappedServices = Services.fromXml(servicesElement.get());
231 recognisedChildren.add(servicesElement.get());
233 mappedServices = new HashMap<>();
235 Services services = Services.resolveServices(mappedServices);
236 // merge with what candidate db contains by default - ref_
238 for(ObjectName existingON: instancesForFillingServiceRefMapping) {
239 logger.trace("Filling services from {}", existingON);
240 // get all its services
241 String factoryName = ObjectNameUtil.getFactoryName(existingON);
242 ModuleConfig moduleConfig = moduleNamesToConfigs.get(factoryName);
244 checkState(moduleConfig != null, "Cannot find ModuleConfig with name " + factoryName + " in " + moduleNamesToConfigs);
245 // Set<String> services = ;
246 for (Entry<String, String> serviceName : moduleConfig.getProvidedServices().entries()) {
248 services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON);
255 private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
257 factoryNameWithPrefix.startsWith(prefixOrEmptyString),
258 format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
259 factoryNameWithPrefix, prefixOrEmptyString));
261 int factoryNameAfterPrefixIndex;
262 if (prefixOrEmptyString.isEmpty()) {
263 factoryNameAfterPrefixIndex = 0;
265 factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
267 return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
270 private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
271 Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
273 Preconditions.checkNotNull(mappingsFromNamespace,
274 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
275 instanceName, factoryName, moduleConfigs.keySet());
277 ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
278 checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
279 return moduleMapping;