org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config.java

Source

/*
 * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;

import static com.google.common.base.Preconditions.checkState;

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.api.xml.XmlNetconfConstants;
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.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class Config {

    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;
    }

    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 (Entry<String, Map<String, ModuleConfig>> namespaceToModuleToConfigEntry : configs.entrySet()) {

            Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();

            for (Entry<String, ModuleConfig> mbeEntry : namespaceToModuleToConfigEntry.getValue().entrySet()) {

                String moduleName = mbeEntry.getKey();
                Collection<ObjectName> instances = moduleToInstances.get(moduleName);

                // 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);

            }

            retVal.put(namespaceToModuleToConfigEntry.getKey(), innerRetVal);
        }
        return retVal;
    }

    private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
        Multimap<String, ObjectName> retVal = HashMultimap.create();

        for (ObjectName objectName : instancesToMap) {
            String factoryName = ObjectNameUtil.getFactoryName(objectName);
            retVal.put(factoryName, objectName);
        }
        return retVal;
    }

    public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
            Element dataElement, ServiceRegistryWrapper serviceTracker) {

        Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
                moduleConfigs);

        if (maybeNamespace.isPresent()) {
            dataElement.setAttributeNS(maybeNamespace.get(), dataElement.getNodeName(), "xmlns");
        }

        Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY,
                Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
        dataElement.appendChild(modulesElement);
        for (Entry<String, Map<String, Collection<ObjectName>>> moduleToInstanceEntry : moduleToInstances
                .entrySet()) {
            for (Entry<String, Collection<ObjectName>> moduleMappingEntry : moduleToInstanceEntry.getValue()
                    .entrySet()) {

                ModuleConfig mapping = moduleConfigs.get(moduleToInstanceEntry.getKey())
                        .get(moduleMappingEntry.getKey());

                if (moduleMappingEntry.getValue().isEmpty()) {
                    continue;
                }

                for (ObjectName objectName : moduleMappingEntry.getValue()) {
                    modulesElement.appendChild(mapping.toXml(objectName, document, moduleToInstanceEntry.getKey()));
                }

            }
        }

        dataElement.appendChild(Services.toXml(serviceTracker, document));

        return dataElement;
    }

    // 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>> 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();

        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);
                }
            };

            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);

        Map<String, Multimap<String, ModuleElementDefinition>> retVal = Maps.newHashMap();

        for (XmlElement moduleElement : moduleElements) {
            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 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);
            modulesElement.get().checkUnrecognisedElements(moduleElements);
        } else {
            moduleElements = Lists.newArrayList();
        }
        return moduleElements;
    }

    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 = null;
        nameElement = moduleElement.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.NAME_KEY);
        String instanceName = nameElement.getTextContent();
        String factoryNameWithPrefix = typeElement.getTextContent();
        String prefixOrEmptyString = prefixToNamespace.getKey();
        String factoryName = getFactoryName(factoryNameWithPrefix, prefixOrEmptyString);

        ModuleConfig moduleMapping = getModuleMapping(moduleNamespace, instanceName, factoryName);

        Multimap<String, T> innerMap = retVal.get(moduleNamespace);
        if (innerMap == null) {
            innerMap = HashMultimap.create();
            retVal.put(moduleNamespace, innerMap);
        }

        T resolvedElement = resolvingStrategy.resolveElement(moduleMapping, moduleElement, serviceTracker,
                instanceName, moduleNamespace, defaultStrategy);

        innerMap.put(factoryName, resolvedElement);
    }

    public Services fromXmlServices(XmlElement xml) throws NetconfDocumentedException {
        Optional<XmlElement> servicesElement = getServicesElement(xml);

        Services services;
        if (servicesElement.isPresent()) {
            services = Services.fromXml(servicesElement.get());
        } else {
            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());
        }

        parent.checkUnrecognisedElements(recognised);
    }

    private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
        checkState(factoryNameWithPrefix.startsWith(prefixOrEmptyString),
                String.format("Internal error: text " + "content '%s' of type node does not start with prefix '%s'",
                        factoryNameWithPrefix, prefixOrEmptyString));

        int factoryNameAfterPrefixIndex;
        if (prefixOrEmptyString.isEmpty()) {
            factoryNameAfterPrefixIndex = 0;
        } else {
            factoryNameAfterPrefixIndex = prefixOrEmptyString.length() + 1;
        }
        return factoryNameWithPrefix.substring(factoryNameAfterPrefixIndex);
    }

    private ModuleConfig getModuleMapping(String moduleNamespace, String instanceName, String factoryName) {
        Map<String, ModuleConfig> mappingsFromNamespace = moduleConfigs.get(moduleNamespace);

        Preconditions.checkNotNull(mappingsFromNamespace,
                "Namespace %s, defined in: module %s of type %s not found, available namespaces: %s",
                moduleNamespace, instanceName, factoryName, moduleConfigs.keySet());

        ModuleConfig moduleMapping = mappingsFromNamespace.get(factoryName);
        checkState(moduleMapping != null, "Cannot find mapping for module type " + factoryName);
        return moduleMapping;
    }

    private interface ResolvingStrategy<T> {
        public T resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement,
                ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace,
                EditStrategyType defaultStrategy) throws NetconfDocumentedException;
    }
}