Fix star import and enable checkstyle rule to prevent it.
[controller.git] / opendaylight / netconf / config-netconf-connector / src / main / java / org / opendaylight / controller / netconf / confignetconfconnector / mapping / config / Config.java
1 /*
2  * Copyright (c) 2013 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.netconf.confignetconfconnector.mapping.config;
10
11 import java.util.Collection;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Map.Entry;
16 import java.util.Set;
17
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;
30
31 import javax.management.ObjectName;
32
33 import static com.google.common.base.Preconditions.checkState;
34 import static java.lang.String.format;
35
36 public class Config {
37
38     private final Map<String, Map<String, ModuleConfig>> moduleConfigs;
39
40     public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
41         this.moduleConfigs = moduleConfigs;
42     }
43
44     private Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
45             Services serviceTracker) {
46         Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
47
48         Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
49
50         for (String namespace : moduleConfigs.keySet()) {
51
52             Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
53
54             for (Entry<String, ModuleConfig> mbeEntry : moduleConfigs.get(namespace).entrySet()) {
55
56                 String moduleName = mbeEntry.getKey();
57                 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
58
59                 if (instances == null)
60                     continue;
61
62                 innerRetVal.put(moduleName, instances);
63
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());
70
71             }
72
73             retVal.put(namespace, innerRetVal);
74         }
75         return retVal;
76     }
77
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);
83             }
84         }
85     }
86
87     private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
88         Multimap<String, ObjectName> retVal = HashMultimap.create();
89
90         for (ObjectName objectName : instancesToMap) {
91             String factoryName = ObjectNameUtil.getFactoryName(objectName);
92             retVal.put(factoryName, objectName);
93         }
94         return retVal;
95     }
96
97     // public Element toXml(Set<ObjectName> instancesToMap, String namespace,
98     // Document document) {
99     // return toXml(instancesToMap, Optional.of(namespace), document);
100     // }
101
102     public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
103             Element dataElement) {
104         Services serviceTracker = new Services();
105
106         Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
107                 serviceTracker);
108
109         Element root = dataElement;
110         if (maybeNamespace.isPresent()) {
111             XmlUtil.addNamespaceAttr(root, maybeNamespace.get());
112         }
113
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)
120                     .entrySet()) {
121
122                 ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
123
124                 if (moduleMappingEntry.getValue().isEmpty()) {
125                     addEmptyModulesCommented(document, modulesElement, moduleNamespace, moduleMappingEntry);
126                 } else {
127                     for (ObjectName objectName : moduleMappingEntry.getValue()) {
128                         modulesElement
129                                 .appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
130                     }
131                 }
132
133             }
134         }
135
136         root.appendChild(serviceTracker.toXml(serviceTracker.getMappedServices(), document));
137
138         return root;
139     }
140
141     private void addEmptyModulesCommented(Document document, Element root, String moduleNamespace,
142             Entry<String, Collection<ObjectName>> moduleMappingEntry) {
143         Element emptyModule = document.createElement(XmlNetconfConstants.MODULE_KEY);
144
145         Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY,
146                 moduleMappingEntry.getKey());
147         emptyModule.appendChild(typeElement);
148
149         root.appendChild(document.createComment(XmlUtil.toString(emptyModule, false)));
150     }
151
152     // TODO refactor, replace string representing namespace with namespace class
153     // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
154     // class
155     public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml) {
156         Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
157
158         List<XmlElement> recognisedChildren = Lists.newArrayList();
159
160         Services serviceTracker = fromXmlServices(xml, recognisedChildren);
161         List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
162
163         xml.checkUnrecognisedElements(recognisedChildren);
164
165         for (XmlElement moduleElement : moduleElements) {
166             resolveModule(retVal, serviceTracker, moduleElement);
167         }
168
169         return retVal;
170     }
171
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);
180         } else {
181             moduleElements = Lists.newArrayList();
182         }
183         return moduleElements;
184     }
185
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);
196
197         ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
198
199         Multimap<String, ModuleElementResolved> innerMap = retVal.get(moduleNamespace);
200         if (innerMap == null) {
201             innerMap = HashMultimap.create();
202             retVal.put(moduleNamespace, innerMap);
203         }
204
205         ModuleElementResolved moduleElementResolved = moduleMapping.fromXml(moduleElement, serviceTracker,
206                 instanceName, moduleNamespace);
207
208         innerMap.put(factoryName, moduleElementResolved);
209     }
210
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);
214
215         Map<String, Map<String, String>> mappedServices;
216         if (servicesElement.isPresent()) {
217             mappedServices = Services.fromXml(servicesElement.get());
218             recognisedChildren.add(servicesElement.get());
219         } else {
220             mappedServices = new HashMap<>();
221         }
222
223         return Services.resolveServices(mappedServices);
224     }
225
226     private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
227         checkState(
228                 factoryNameWithPrefix.startsWith(prefixOrEmptyString),
229                 format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
230                         factoryNameWithPrefix, prefixOrEmptyString));
231
232         int factoryNameAfterPrefixIndex;
233         if (prefixOrEmptyString.isEmpty()) {
234             factoryNameAfterPrefixIndex = 0;
235         } else {
236             factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
237         }
238         return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
239     }
240
241     private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
242         Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);
243
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());
247
248         ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
249         checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
250         return moduleMapping;
251     }
252
253 }