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 java.util.Collection;
12 import java.util.HashMap;
13 import java.util.List;
15 import java.util.Map.Entry;
18 import com.google.common.base.Optional;
19 import com.google.common.base.Preconditions;
20 import com.google.common.collect.HashMultimap;
21 import com.google.common.collect.Lists;
22 import com.google.common.collect.Maps;
23 import com.google.common.collect.Multimap;
24 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
25 import org.opendaylight.controller.netconf.util.xml.XmlElement;
26 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
27 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
28 import org.w3c.dom.Document;
29 import org.w3c.dom.Element;
31 import javax.management.ObjectName;
33 import static com.google.common.base.Preconditions.checkState;
34 import static java.lang.String.format;
38 private final Map<String, Map<String, ModuleConfig>> moduleConfigs;
40 public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
41 this.moduleConfigs = moduleConfigs;
44 private Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
45 Services serviceTracker) {
46 Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
48 Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
50 for (String namespace : moduleConfigs.keySet()) {
52 Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
54 for (Entry<String, ModuleConfig> mbeEntry : moduleConfigs.get(namespace).entrySet()) {
56 String moduleName = mbeEntry.getKey();
57 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
59 if (instances == null)
62 innerRetVal.put(moduleName, instances);
64 // All found instances add to service tracker in advance
65 // This way all instances will be serialized as all available
66 // services when get-config is triggered
67 // (even if they are not used as services by other onstances)
68 // = more user friendly
69 addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
73 retVal.put(namespace, innerRetVal);
78 private void addServices(Services serviceTracker, Collection<ObjectName> instances,
79 Collection<String> providedServices) {
80 for (ObjectName instanceOn : instances) {
81 for (String serviceName : providedServices) {
82 serviceTracker.addServiceEntry(serviceName, instanceOn);
87 private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
88 Multimap<String, ObjectName> retVal = HashMultimap.create();
90 for (ObjectName objectName : instancesToMap) {
91 String factoryName = ObjectNameUtil.getFactoryName(objectName);
92 retVal.put(factoryName, objectName);
97 // public Element toXml(Set<ObjectName> instancesToMap, String namespace,
98 // Document document) {
99 // return toXml(instancesToMap, Optional.of(namespace), document);
102 public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
103 Element dataElement) {
104 Services serviceTracker = new Services();
106 Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
109 Element root = dataElement;
110 if (maybeNamespace.isPresent()) {
111 XmlUtil.addNamespaceAttr(root, maybeNamespace.get());
114 Element modulesElement = document.createElement(XmlNetconfConstants.MODULES_KEY);
115 XmlUtil.addNamespaceAttr(modulesElement,
116 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
117 root.appendChild(modulesElement);
118 for (String moduleNamespace : moduleToInstances.keySet()) {
119 for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstances.get(moduleNamespace)
122 ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
124 if (moduleMappingEntry.getValue().isEmpty()) {
125 addEmptyModulesCommented(document, modulesElement, moduleNamespace, moduleMappingEntry);
127 for (ObjectName objectName : moduleMappingEntry.getValue()) {
129 .appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
136 root.appendChild(serviceTracker.toXml(serviceTracker.getMappedServices(), document));
141 private void addEmptyModulesCommented(Document document, Element root, String moduleNamespace,
142 Entry<String, Collection<ObjectName>> moduleMappingEntry) {
143 Element emptyModule = document.createElement(XmlNetconfConstants.MODULE_KEY);
145 Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY,
146 moduleMappingEntry.getKey());
147 emptyModule.appendChild(typeElement);
149 root.appendChild(document.createComment(XmlUtil.toString(emptyModule, false)));
152 // TODO refactor, replace string representing namespace with namespace class
153 // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
155 public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml) {
156 Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
158 List<XmlElement> recognisedChildren = Lists.newArrayList();
160 Services serviceTracker = fromXmlServices(xml, recognisedChildren);
161 List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
163 xml.checkUnrecognisedElements(recognisedChildren);
165 for (XmlElement moduleElement : moduleElements) {
166 resolveModule(retVal, serviceTracker, moduleElement);
172 private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
173 Optional<XmlElement> modulesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
174 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
175 List<XmlElement> moduleElements;
176 if (modulesElement.isPresent()) {
177 moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
178 recognisedChildren.add(modulesElement.get());
179 modulesElement.get().checkUnrecognisedElements(moduleElements);
181 moduleElements = Lists.newArrayList();
183 return moduleElements;
186 private void resolveModule(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker,
187 XmlElement moduleElement) {
188 XmlElement typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
189 Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
190 String moduleNamespace = prefixToNamespace.getValue();
191 XmlElement nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
192 String instanceName = nameElement.getTextContent();
193 String factoryNameWithPrefix = typeElement.getTextContent();
194 String prefixOrEmptyString = prefixToNamespace.getKey();
195 String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);
197 ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
199 Multimap<String, ModuleElementResolved> innerMap = retVal.get(moduleNamespace);
200 if (innerMap == null) {
201 innerMap = HashMultimap.create();
202 retVal.put(moduleNamespace, innerMap);
205 ModuleElementResolved moduleElementResolved = moduleMapping.fromXml(moduleElement, serviceTracker,
206 instanceName, moduleNamespace);
208 innerMap.put(factoryName, moduleElementResolved);
211 private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren) {
212 Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
213 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
215 Map<String, Map<String, String>> mappedServices;
216 if (servicesElement.isPresent()) {
217 mappedServices = Services.fromXml(servicesElement.get());
218 recognisedChildren.add(servicesElement.get());
220 mappedServices = new HashMap<>();
223 return Services.resolveServices(mappedServices);
226 private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
228 factoryNameWithPrefix.startsWith(prefixOrEmptyString),
229 format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
230 factoryNameWithPrefix, prefixOrEmptyString));
232 int factoryNameAfterPrefixIndex;
233 if (prefixOrEmptyString.isEmpty()) {
234 factoryNameAfterPrefixIndex = 0;
236 factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
238 return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
241 private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
242 Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
244 Preconditions.checkNotNull(mappingsFromNamespace,
245 "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s", moduleNamespace,
246 instanceName, factoryName, moduleConfigs.keySet());
248 ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
249 checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
250 return moduleMapping;