package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.management.ObjectName;
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-
-import javax.management.ObjectName;
-
import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
+
public class Config {
- private final Map<String, Map<String, ModuleConfig>> moduleConfigs;
+ private final Map<String/* Namespace from yang file */,
+ Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
+
+ private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
+ this(moduleConfigs, Collections.<String, Map<Date, EditConfig.IdentityMapping>>emptyMap());
+ }
+
+ public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
this.moduleConfigs = moduleConfigs;
+ this.identityMap = identityMap;
}
- private Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
- Services serviceTracker) {
+ public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
+ Map<String, Map<String, ModuleConfig>> configs) {
Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
- for (String namespace : moduleConfigs.keySet()) {
+ for (String namespace : configs.keySet()) {
Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
- for (Entry<String, ModuleConfig> mbeEntry : moduleConfigs.get(namespace).entrySet()) {
+ for (Entry<String, ModuleConfig> mbeEntry : configs.get(namespace).entrySet()) {
String moduleName = mbeEntry.getKey();
Collection<ObjectName> instances = moduleToInstances.get(moduleName);
- if (instances == null)
+ // TODO, this code does not support same module names from different namespaces
+ // Namespace should be present in ObjectName
+
+ if (instances == null){
continue;
+ }
innerRetVal.put(moduleName, instances);
- // All found instances add to service tracker in advance
- // This way all instances will be serialized as all available
- // services when get-config is triggered
- // (even if they are not used as services by other onstances)
- // = more user friendly
- addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
-
}
retVal.put(namespace, innerRetVal);
return retVal;
}
- private void addServices(Services serviceTracker, Collection<ObjectName> instances,
- Collection<String> providedServices) {
- for (ObjectName instanceOn : instances) {
- for (String serviceName : providedServices) {
- serviceTracker.addServiceEntry(serviceName, instanceOn);
- }
- }
- }
-
private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
Multimap<String, ObjectName> retVal = HashMultimap.create();
return retVal;
}
- // public Element toXml(Set<ObjectName> instancesToMap, String namespace,
- // Document document) {
- // return toXml(instancesToMap, Optional.of(namespace), document);
- // }
-
public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
- Element dataElement) {
- Services serviceTracker = new Services();
+ Element dataElement, ServiceRegistryWrapper serviceTracker) {
Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
- serviceTracker);
+ moduleConfigs);
Element root = dataElement;
if (maybeNamespace.isPresent()) {
- XmlUtil.addNamespaceAttr(root, maybeNamespace.get());
+ root.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
}
- Element modulesElement = document.createElement(XmlNetconfConstants.MODULES_KEY);
- XmlUtil.addNamespaceAttr(modulesElement,
- XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
root.appendChild(modulesElement);
for (String moduleNamespace : moduleToInstances.keySet()) {
for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstances.get(moduleNamespace)
ModuleConfig mapping = moduleConfigs.get(moduleNamespace).get(moduleMappingEntry.getKey());
if (moduleMappingEntry.getValue().isEmpty()) {
- addEmptyModulesCommented(document, modulesElement, moduleNamespace, moduleMappingEntry);
- } else {
- for (ObjectName objectName : moduleMappingEntry.getValue()) {
- modulesElement
- .appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
- }
+ continue;
+ }
+
+ for (ObjectName objectName : moduleMappingEntry.getValue()) {
+ modulesElement.appendChild(mapping.toXml(objectName, serviceTracker, document, moduleNamespace));
}
}
}
- root.appendChild(serviceTracker.toXml(serviceTracker.getMappedServices(), document));
+ root.appendChild(Services.toXml(serviceTracker, document));
return root;
}
- private void addEmptyModulesCommented(Document document, Element root, String moduleNamespace,
- Entry<String, Collection<ObjectName>> moduleMappingEntry) {
- Element emptyModule = document.createElement(XmlNetconfConstants.MODULE_KEY);
-
- Element typeElement = XmlUtil.createTextElement(document, XmlNetconfConstants.TYPE_KEY,
- moduleMappingEntry.getKey());
- emptyModule.appendChild(typeElement);
-
- root.appendChild(document.createComment(XmlUtil.toString(emptyModule, false)));
- }
-
// TODO refactor, replace string representing namespace with namespace class
// TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved
// class
- public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml) {
+
+ public Map<String, Multimap<String, ModuleElementResolved>> fromXmlModulesResolved(XmlElement xml, EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
+ Optional<XmlElement> modulesElement = getModulesElement(xml);
+ List<XmlElement> moduleElements = getModulesElementList(modulesElement);
+
Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
- List<XmlElement> recognisedChildren = Lists.newArrayList();
+ for (XmlElement moduleElement : moduleElements) {
+ ResolvingStrategy<ModuleElementResolved> resolvingStrategy = new ResolvingStrategy<ModuleElementResolved>() {
+ @Override
+ public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException {
+ return moduleMapping.fromXml(moduleElement, serviceTracker,
+ instanceName, moduleNamespace, defaultStrategy, identityMap);
+ }
+ };
- Services serviceTracker = fromXmlServices(xml, recognisedChildren);
- List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
+ resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
+ }
+ return retVal;
+ }
+
+ /**
+ * return a map containing namespace -> moduleName -> instanceName map. Attribute parsing is omitted.
+ */
+ public Map<String, Multimap<String, ModuleElementDefinition>> fromXmlModulesMap(XmlElement xml,
+ EditStrategyType defaultEditStrategyType, ServiceRegistryWrapper serviceTracker) throws NetconfDocumentedException {
+ Optional<XmlElement> modulesElement = getModulesElement(xml);
+ List<XmlElement> moduleElements = getModulesElementList(modulesElement);
- xml.checkUnrecognisedElements(recognisedChildren);
+ Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();
for (XmlElement moduleElement : moduleElements) {
- resolveModule(retVal, serviceTracker, moduleElement);
- }
+ ResolvingStrategy<ModuleElementDefinition> resolvingStrategy = new ResolvingStrategy<ModuleElementDefinition>() {
+ @Override
+ public ModuleElementDefinition resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
+ ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
+ EditStrategyType defaultStrategy) {
+ // TODO: add check for conflicts between global and local
+ // edit strategy
+ String perInstanceEditStrategy = moduleElement.getAttribute(XmlNetconfConstants.OPERATION_ATTR_KEY,
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+ return new ModuleElementDefinition(instanceName, perInstanceEditStrategy, defaultStrategy);
+ }
+ };
+ resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType, resolvingStrategy);
+ }
return retVal;
}
- private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
- Optional<XmlElement> modulesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
- XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ private static Optional<XmlElement> getModulesElement(XmlElement xml) {
+ return xml.getOnlyChildElementOptionally(XmlNetconfConstants.MODULES_KEY,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ }
+
+ private List<XmlElement> getModulesElementList(Optional<XmlElement> modulesElement) throws NetconfDocumentedException {
List<XmlElement> moduleElements;
+
if (modulesElement.isPresent()) {
moduleElements = modulesElement.get().getChildElementsWithSameNamespace(XmlNetconfConstants.MODULE_KEY);
- recognisedChildren.add(modulesElement.get());
modulesElement.get().checkUnrecognisedElements(moduleElements);
} else {
moduleElements = Lists.newArrayList();
return moduleElements;
}
- private void resolveModule(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker,
- XmlElement moduleElement) {
- XmlElement typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
+ private <T> void resolveModule(Map<String, Multimap<String, T>> retVal, ServiceRegistryWrapper serviceTracker,
+ XmlElement moduleElement, EditStrategyType defaultStrategy, ResolvingStrategy<T> resolvingStrategy) throws NetconfDocumentedException {
+ XmlElement typeElement = null;
+ typeElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.TYPE_KEY);
Entry<String, String> prefixToNamespace = typeElement.findNamespaceOfTextContent();
String moduleNamespace = prefixToNamespace.getValue();
- XmlElement nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
+ XmlElement nameElement = null;
+ nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
String instanceName = nameElement.getTextContent();
String factoryNameWithPrefix = typeElement.getTextContent();
String prefixOrEmptyString = prefixToNamespace.getKey();
ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);
- Multimap<String, ModuleElementResolved> innerMap = retVal.get(moduleNamespace);
+ Multimap<String, T> innerMap = retVal.get(moduleNamespace);
if (innerMap == null) {
innerMap = HashMultimap.create();
retVal.put(moduleNamespace, innerMap);
}
- ModuleElementResolved moduleElementResolved = moduleMapping.fromXml(moduleElement, serviceTracker,
- instanceName, moduleNamespace);
+ T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
+ instanceName, moduleNamespace, defaultStrategy);
- innerMap.put(factoryName, moduleElementResolved);
+ innerMap.put(factoryName, resolvedElement);
}
- private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren) {
- Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
- XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ public Services fromXmlServices(XmlElement xml) throws NetconfDocumentedException {
+ Optional<XmlElement> servicesElement = getServicesElement(xml);
- Map<String, Map<String, String>> mappedServices;
+ Services services;
if (servicesElement.isPresent()) {
- mappedServices = Services.fromXml(servicesElement.get());
- recognisedChildren.add(servicesElement.get());
+ services = Services.fromXml(servicesElement.get());
} else {
- mappedServices = new HashMap<>();
+ services = new Services();
+ }
+
+ return services;
+ }
+
+ private static Optional<XmlElement> getServicesElement(XmlElement xml) {
+ return xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
+ XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ }
+
+ public static void checkUnrecognisedChildren(XmlElement parent) throws NetconfDocumentedException {
+ Optional<XmlElement> servicesOpt = getServicesElement(parent);
+ Optional<XmlElement> modulesOpt = getModulesElement(parent);
+
+ List<XmlElement> recognised = Lists.newArrayList();
+ if(servicesOpt.isPresent()){
+ recognised.add(servicesOpt.get());
+ }
+ if(modulesOpt.isPresent()){
+ recognised.add(modulesOpt.get());
}
- return Services.resolveServices(mappedServices);
+ parent.checkUnrecognisedElements(recognised);
}
private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
checkState(
factoryNameWithPrefix.startsWith(prefixOrEmptyString),
- format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
+ String.format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
factoryNameWithPrefix, prefixOrEmptyString));
int factoryNameAfterPrefixIndex;
return moduleMapping;
}
+ private interface ResolvingStrategy<T> {
+ public T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker,
+ String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException;
+ }
}