From 237c7309b595b59641dfb4eb546412fd12f52d16 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Mon, 9 Dec 2013 14:31:53 +0100 Subject: [PATCH] Added support for persistance of service references to netconf. Created reference names under services/ subtree are now persisted and available for further edit-config operations. Change-Id: I366eaab457e9264d266e16eb4e1a1ad8d97d33bc Signed-off-by: Maros Marsalek --- .../attributes/AttributesConstants.java | 17 ++ .../ObjectNameAttributeMappingStrategy.java | 7 +- .../ObjectNameAttributeResolvingStrategy.java | 3 + .../mapping/config/Config.java | 71 +++---- .../mapping/config/InstanceConfig.java | 5 +- .../config/InstanceConfigElementResolved.java | 10 +- .../mapping/config/ModuleConfig.java | 2 +- .../mapping/config/Services.java | 189 ++++++++++++------ .../mapping/runtime/Runtime.java | 7 +- .../AbstractEditConfigStrategy.java | 20 +- .../editconfig/DeleteEditConfigStrategy.java | 26 ++- .../operations/editconfig/EditConfig.java | 51 ++++- .../editconfig/EditConfigStrategy.java | 3 +- .../editconfig/EditConfigXmlParser.java | 37 ++-- .../editconfig/EditStrategyType.java | 10 +- .../editconfig/MergeEditConfigStrategy.java | 52 ++++- .../editconfig/NoneEditConfigStrategy.java | 3 +- .../editconfig/RemoveEditConfigStrategy.java | 3 +- .../editconfig/ReplaceEditConfigStrategy.java | 53 ++++- .../operations/get/Get.java | 10 +- .../operations/getconfig/GetConfig.java | 10 +- .../osgi/NetconfOperationProvider.java | 2 +- .../transactions/TransactionProvider.java | 8 +- .../NetconfMappingTest.java | 111 +++++++++- .../ServiceTrackerTest.java | 41 ---- .../operations/editconfig/EditConfigTest.java | 44 ++-- .../ReplaceEditConfigStrategyTest.java | 2 +- .../resources/netconfMessages/editConfig.xml | 22 +- .../editConfig_addServiceName.xml | 34 ++++ .../editConfig_merge_threadfactory.xml | 12 +- .../netconfMessages/editConfig_none.xml | 31 +-- .../netconfMessages/editConfig_remove.xml | 11 +- .../test/resources/netconfMessages/rpc.xml | 2 +- .../resources/netconfMessages/rpcInner.xml | 2 +- .../rpcInnerInner_complex_output.xml | 2 +- 35 files changed, 615 insertions(+), 298 deletions(-) create mode 100644 opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java create mode 100644 opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java new file mode 100644 index 0000000000..4f9e1fe087 --- /dev/null +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java @@ -0,0 +1,17 @@ +/** + * @author Maros Marsalek + * + * 12 2013 + * + * Copyright (c) 2012 by Cisco Systems, Inc. + * All rights reserved. + */ +package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes; + +public class AttributesConstants { + + /** + * Property placed into object names for dependencies to preserve reference name + */ + public static final String REF_NAME_ON_PROPERTY_KEY = "X-refName"; +} diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java index f4d88c7c8e..8426341636 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.util.Util; @@ -42,7 +43,11 @@ public class ObjectNameAttributeMappingStrategy extends Util.checkType(value, ObjectName.class); ObjectName on = (ObjectName) value; - String refName = tracker.addServiceEntry(namespace, serviceName, on); + + String expectedRefName = on.getKeyProperty(AttributesConstants.REF_NAME_ON_PROPERTY_KEY); + + String refName = expectedRefName == null ? tracker.getRefName(namespace, serviceName, on, Optional. absent()) + : tracker.getRefName(namespace, serviceName, on, Optional.of(expectedRefName)); return Optional.of(new MappedDependency(namespace, serviceName, refName)); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java index c6f306b360..d8f0e2357e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri import com.google.common.base.Optional; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributesConstants; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance; @@ -46,6 +47,8 @@ public class ObjectNameAttributeResolvingStrategy extends AbstractAttributeResol ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(namespace, serviceName, refName); ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName()); + on = ObjectNameUtil.createON(on.toString() + "," + AttributesConstants.REF_NAME_ON_PROPERTY_KEY + "=" + refName); + logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType()); return Optional.of(on); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java index f33a32271f..3a5fa1170f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java @@ -14,6 +14,7 @@ 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 org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -53,7 +54,7 @@ public class Config { } public static Map>> getMappedInstances(Set instancesToMap, - Services serviceTracker, Map> configs) { + Map> configs) { Multimap moduleToInstances = mapInstancesToModules(instancesToMap); Map>> retVal = Maps.newLinkedHashMap(); @@ -75,13 +76,6 @@ public class Config { 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 instances) - // = more user friendly - addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices()); - } retVal.put(namespace, innerRetVal); @@ -89,15 +83,6 @@ public class Config { return retVal; } - private static void addServices(Services serviceTracker, Collection instances, - Multimap providedServices) { - for (ObjectName instanceOn : instances) { - for (Entry serviceName : providedServices.entries()) { - serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn); - } - } - } - private static Multimap mapInstancesToModules(Set instancesToMap) { Multimap retVal = HashMultimap.create(); @@ -114,11 +99,10 @@ public class Config { // } public Element toXml(Set instancesToMap, Optional maybeNamespace, Document document, - Element dataElement) { - Services serviceTracker = new Services(); + Element dataElement, Services serviceTracker) { Map>> moduleToInstances = getMappedInstances(instancesToMap, - serviceTracker, moduleConfigs); + moduleConfigs); Element root = dataElement; if (maybeNamespace.isPresent()) { @@ -167,13 +151,13 @@ public class Config { // TODO refactor, replace string representing namespace with namespace class // TODO refactor, replace Map->Multimap with e.g. ConfigElementResolved // class - public Map> fromXml(XmlElement xml, Set instancesForFillingServiceRefMapping, - EditStrategyType defaultEditStrategyType) { + public ConfigElementResolved fromXml(XmlElement xml, + EditStrategyType defaultEditStrategyType, ServiceReferenceReadableRegistry taClient) { Map> retVal = Maps.newHashMap(); List recognisedChildren = Lists.newArrayList(); - Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping); + Services serviceTracker = fromXmlServices(xml, recognisedChildren, taClient); List moduleElements = fromXmlModules(xml, recognisedChildren); xml.checkUnrecognisedElements(recognisedChildren); @@ -182,7 +166,26 @@ public class Config { resolveModule(retVal, serviceTracker, moduleElement, defaultEditStrategyType); } - return retVal; + return new ConfigElementResolved(retVal, serviceTracker); + } + + public static class ConfigElementResolved { + + private final Map> resolvedModules; + private final Services services; + + public ConfigElementResolved(Map> retVal, Services serviceTracker) { + this.resolvedModules = retVal; + this.services = serviceTracker; + } + + public Map> getResolvedModules() { + return resolvedModules; + } + + public Services getServices() { + return services; + } } private List fromXmlModules(XmlElement xml, List recognisedChildren) { @@ -224,7 +227,8 @@ public class Config { innerMap.put(factoryName, moduleElementResolved); } - private Services fromXmlServices(XmlElement xml, List recognisedChildren, Set instancesForFillingServiceRefMapping) { + private Services fromXmlServices(XmlElement xml, List recognisedChildren, + ServiceReferenceReadableRegistry taClient) { Optional servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG); @@ -235,22 +239,7 @@ public class Config { } else { mappedServices = new HashMap<>(); } - Services services = Services.resolveServices(mappedServices); - // merge with what candidate db contains by default - ref_ - - for(ObjectName existingON: instancesForFillingServiceRefMapping) { - logger.trace("Filling services from {}", existingON); - // get all its services - String factoryName = ObjectNameUtil.getFactoryName(existingON); - ModuleConfig moduleConfig = moduleNamesToConfigs.get(factoryName); - - checkState(moduleConfig != null, "Cannot find ModuleConfig with name " + factoryName + " in " + moduleNamesToConfigs); - // Set services = ; - for (Entry serviceName : moduleConfig.getProvidedServices().entries()) { - - services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON); - } - } + Services services = Services.resolveServices(mappedServices, taClient); return services; } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java index 33858746cb..aae1636165 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java @@ -12,6 +12,7 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry; import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; @@ -128,7 +129,7 @@ public final class InstanceConfig { } public InstanceConfigElementResolved fromXml(XmlElement moduleElement, Services services, String moduleNamespace, - EditStrategyType defaultStrategy) { + EditStrategyType defaultStrategy, Multimap providedServices) { Map retVal = Maps.newHashMap(); Map strats = new ObjectXmlReader().prepareReading(yangToAttrConfig); @@ -153,7 +154,7 @@ public final class InstanceConfig { XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved( - retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy); + retVal, defaultStrategy, providedServices) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy, providedServices); resolveConfiguration(instanceConfigElementResolved, services); return instanceConfigElementResolved; diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java index e4bd9212e9..55cb60bed5 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; import com.google.common.base.Preconditions; +import com.google.common.collect.Multimap; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigStrategy; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser; @@ -24,16 +25,19 @@ public class InstanceConfigElementResolved { private final EditStrategyType editStrategy; private final Map configuration; + private final Multimap providedServices; - public InstanceConfigElementResolved(String currentStrategy, Map configuration, EditStrategyType defaultStrategy) { + public InstanceConfigElementResolved(String currentStrategy, Map configuration, EditStrategyType defaultStrategy, Multimap providedServices) { EditStrategyType valueOf = checkStrategy(currentStrategy, defaultStrategy); this.editStrategy = valueOf; this.configuration = configuration; + this.providedServices = providedServices; } - public InstanceConfigElementResolved(Map configuration, EditStrategyType defaultStrategy) { + public InstanceConfigElementResolved(Map configuration, EditStrategyType defaultStrategy, Multimap providedServices) { editStrategy = defaultStrategy; this.configuration = configuration; + this.providedServices = providedServices; } @@ -54,7 +58,7 @@ public class InstanceConfigElementResolved { public EditConfigStrategy getEditStrategy() { - return editStrategy.getFittingStrategy(); + return editStrategy.getFittingStrategy(providedServices); } public Map getConfiguration() { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java index 2e2a26400f..2ac6fe0a9b 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java @@ -87,7 +87,7 @@ public class ModuleConfig { public ModuleElementResolved fromXml(XmlElement moduleElement, Services depTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) { - InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy); + InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, providedServices); return new ModuleElementResolved(instanceName, ice); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java index f522668733..a4f5e4999c 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java @@ -9,10 +9,14 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; @@ -22,9 +26,9 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -import javax.annotation.Nullable; import javax.management.ObjectName; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -33,6 +37,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Services { + private static final Logger logger = LoggerFactory.getLogger(Services.class); private static final String PROVIDER_KEY = "provider"; @@ -42,58 +47,33 @@ public final class Services { private long suffix = 1; - private final Map instanceToRef = Maps.newHashMap(); private final Map>> namespaceToServiceNameToRefNameToInstance = Maps .newHashMap(); + private ServiceReferenceReadableRegistry configServiceRefRegistry; - public String addServiceEntry(String namespace, String serviceName, ObjectName on) { - - String moduleName = on.getKeyProperty("moduleFactoryName"); - String instanceName = on.getKeyProperty("instanceName"); - - String refName = addServiceEntry(namespace, serviceName, moduleName, instanceName); - logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}", - serviceName, refName, moduleName, instanceName); - return refName; + public Services(ServiceReferenceReadableRegistry configServiceRefRegistry) { + this.configServiceRefRegistry = configServiceRefRegistry; } @VisibleForTesting - public String addServiceEntry(String namespace, String serviceName, String moduleName, String instanceName) { - ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName); - serviceInstance.setServiceName(serviceName); + public String getNewDefaultRefName(String namespace, String serviceName, String moduleName, String instanceName) { + String refName; + refName = "ref_" + instanceName; - String refName = instanceToRef.get(serviceInstance); + Map> serviceNameToRefNameToInstance = getMappedServices().get(namespace); - Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace); - if (serviceNameToRefNameToInstance == null) { - serviceNameToRefNameToInstance = Maps.newHashMap(); - namespaceToServiceNameToRefNameToInstance.put(namespace, serviceNameToRefNameToInstance); - } + Map refNameToInstance; + if(serviceNameToRefNameToInstance == null || serviceNameToRefNameToInstance.containsKey(serviceName) == false) { + refNameToInstance = Collections.emptyMap(); + } else + refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); - Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); - if (refNameToInstance == null) { - refNameToInstance = Maps.newHashMap(); - serviceNameToRefNameToInstance.put(serviceName, refNameToInstance); + final Set refNamesAsSet = toSet(refNameToInstance.keySet()); + if (refNamesAsSet.contains(refName)) { + refName = findAvailableRefName(refName, refNamesAsSet); } - if (refName != null) { - if (serviceNameToRefNameToInstance.get(serviceName).containsKey(moduleName) == false) { - refNameToInstance.put(refName, serviceInstance); - } - return refName; - } else { - refName = "ref_" + instanceName; - - final Set refNamesAsSet = toSet(instanceToRef.values()); - if (refNamesAsSet.contains(refName)) { - refName = findAvailableRefName(refName, refNamesAsSet); - } - - instanceToRef.put(serviceInstance, refName); - refNameToInstance.put(refName, serviceInstance); - - return refName; - } + return refName; } private Set toSet(Collection values) { @@ -109,15 +89,15 @@ public final class Services { } public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) { - Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace); - Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace + " , " - + serviceNameToRefNameToInstance.keySet()); + Map> serviceNameToRefNameToInstance = getMappedServices().get(namespace); + + Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace); - Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); + Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , " + serviceNameToRefNameToInstance.keySet()); - ServiceInstance serviceInstance = refNameToInstance.get(refName); + ServiceInstance serviceInstance = ServiceInstance.fromString(refNameToInstance.get(refName)); Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName + " under service name " + serviceName + " , " + refNameToInstance.keySet()); return serviceInstance; @@ -136,26 +116,61 @@ public final class Services { for (String serviceName : serviceNameToRefNameToInstance.keySet()) { - Map innerInnerRetVal = Maps.transformValues( - serviceNameToRefNameToInstance.get(serviceName), new Function() { - @Nullable - @Override - public String apply(@Nullable ServiceInstance serviceInstance) { - return serviceInstance.toString(); - } - }); + Map innerInnerRetVal = Maps.newHashMap(); + for (Entry refNameToSi : serviceNameToRefNameToInstance.get(serviceName).entrySet()) { + innerInnerRetVal.put(refNameToSi.getKey(), refNameToSi.getValue().toString()); + } innerRetVal.put(serviceName, innerInnerRetVal); } retVal.put(namespace, innerRetVal); } + Map> serviceMapping = configServiceRefRegistry.getServiceMapping(); + for (String serviceQName : serviceMapping.keySet()) + for (String refName : serviceMapping.get(serviceQName).keySet()) { + + ObjectName on = serviceMapping.get(serviceQName).get(refName); + ServiceInstance si = ServiceInstance.fromObjectName(on); + + // FIXME use QName's new String constructor, after its implemented + Pattern p = Pattern.compile("\\(([^\\(\\?]+)\\?[^\\?\\)]*\\)([^\\)]+)"); + Matcher matcher = p.matcher(serviceQName); + Preconditions.checkArgument(matcher.matches()); + String namespace = matcher.group(1); + String localName = matcher.group(2); + + Map> serviceToRefs = retVal.get(namespace); + if(serviceToRefs==null) { + serviceToRefs = Maps.newHashMap(); + retVal.put(namespace, serviceToRefs); + } + + Map refsToSis = serviceToRefs.get(localName); + if(refsToSis==null) { + refsToSis = Maps.newHashMap(); + serviceToRefs.put(localName, refsToSis); + } + + Preconditions.checkState(refsToSis.containsKey(refName) == false, + "Duplicate reference name %s for service %s:%s, now for instance %s", refName, namespace, + localName, on); + refsToSis.put(refName, si.toString()); + } + return retVal; } + /** + * + */ + public Map>> getNamespaceToServiceNameToRefNameToInstance() { + return namespaceToServiceNameToRefNameToInstance; + } + // TODO hide resolveServices, call it explicitly in fromXml - public static Services resolveServices(Map>> mappedServices) { - Services tracker = new Services(); + public static Services resolveServices(Map>> mappedServices, ServiceReferenceReadableRegistry taClient) { + Services tracker = new Services(taClient); for (Entry>> namespaceEntry : mappedServices.entrySet()) { String namespace = namespaceEntry.getKey(); @@ -179,18 +194,18 @@ public final class Services { } String refName = refEntry.getKey(); - Preconditions.checkState(false == refNameToInstance.containsKey(refName), - "Duplicate reference name to service " + refName + " under service " + serviceName); + ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue()); refNameToInstance.put(refName, serviceInstance); - tracker.instanceToRef.put(serviceInstance, refEntry.getKey()); } } } return tracker; } + // TODO support edit strategies on services + public static Map>> fromXml(XmlElement xml) { Map>> retVal = Maps.newHashMap(); @@ -275,6 +290,51 @@ public final class Services { return root; } + public String getRefName(String namespace, String serviceName, ObjectName on, Optional expectedRefName) { + Optional refNameOptional = getRefNameOptional(namespace, serviceName, on, expectedRefName); + Preconditions.checkState(refNameOptional.isPresent(), "No reference names mapped to %s, %s, %s", namespace, + serviceName, on); + return refNameOptional.get(); + } + + public Optional getRefNameOptional(String namespace, String serviceName, ObjectName on, + Optional expectedRefName) { + Map> services = getMappedServices().get(namespace); + + if(services == null) return Optional.absent(); + Map refs = services.get(serviceName); + + if(refs == null) return Optional.absent(); + Multimap reverted = revertMap(refs); + + ServiceInstance serviceInstance = ServiceInstance.fromObjectName(on); + Collection references = reverted.get(serviceInstance); + + if (expectedRefName.isPresent() && references.contains(expectedRefName.get())) { + logger.debug("Returning expected ref name {} for {}", expectedRefName.get(), on); + return expectedRefName; + } else if (references.size() > 0) { + String next = references.iterator().next(); + logger.debug("Returning random ref name {} for {}", next, on); + return Optional.of(next); + } else + return Optional.absent(); + } + + private Multimap revertMap(Map refs) { + Multimap multimap = HashMultimap.create(); + + for (Entry e : refs.entrySet()) { + multimap.put(ServiceInstance.fromString(e.getValue()), e.getKey()); + } + + return multimap; + } + + public boolean hasRefName(String key, String value, ObjectName on) { + return getRefNameOptional(key, value, on, Optional.absent()).isPresent(); + } + public static final class ServiceInstance { public ServiceInstance(String moduleName, String instanceName) { this.moduleName = moduleName; @@ -372,6 +432,13 @@ public final class Services { return true; } + public ObjectName getObjectName(String transactionName) { + return ObjectNameUtil.createTransactionModuleON(transactionName, moduleName, instanceName); + } + + public static ServiceInstance fromObjectName(ObjectName on) { + return new ServiceInstance(ObjectNameUtil.getFactoryName(on), ObjectNameUtil.getInstanceName(on)); + } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java index 64f295a4d8..89c782c51c 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runti import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig; @@ -60,8 +61,8 @@ public class Runtime { return retVal; } - public Element toXml(Set instancesToMap, Set configBeans, Document document) { - Services serviceTracker = new Services(); + public Element toXml(Set instancesToMap, Set configBeans, Document document, ServiceReferenceReadableRegistry serviceRegistry) { + Services serviceTracker = new Services(serviceRegistry); Element root = document.createElement(XmlNetconfConstants.DATA_KEY); @@ -72,7 +73,7 @@ public class Runtime { Map> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap); Map>> moduleToConfigInstance = Config.getMappedInstances( - configBeans, serviceTracker, moduleConfigs); + configBeans, moduleConfigs); for (String localNamespace : moduleConfigs.keySet()) { diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java index d8ea7d7af7..65df965afd 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java @@ -8,38 +8,38 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; - -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; + public abstract class AbstractEditConfigStrategy implements EditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(AbstractEditConfigStrategy.class); @Override public void executeConfiguration(String module, String instance, Map configuration, - ConfigTransactionClient ta) { + ConfigTransactionClient ta, Services services) { try { ObjectName on = ta.lookupConfigBean(module, instance); logger.debug("ServiceInstance for {} {} located successfully under {}", module, instance, on); - executeStrategy(configuration, ta, on); + executeStrategy(configuration, ta, on, services); } catch (InstanceNotFoundException e) { - handleMissingInstance(configuration, ta, module, instance); + handleMissingInstance(configuration, ta, module, instance, services); } } abstract void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance); + String module, String instance, Services services); abstract void executeStrategy(Map configuration, ConfigTransactionClient ta, - ObjectName objectName); + ObjectName objectName, Services services); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java index ffe107f8ce..12beaf8f8e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java @@ -8,28 +8,40 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; - -import javax.management.InstanceNotFoundException; -import javax.management.ObjectName; - +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; + public class DeleteEditConfigStrategy extends AbstractEditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(DeleteEditConfigStrategy.class); + private final Multimap providedServices; + + public DeleteEditConfigStrategy() { + this.providedServices = HashMultimap.create(); + } + + public DeleteEditConfigStrategy(Multimap providedServices) { + this.providedServices = providedServices; + } + @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { + String module, String instance, Services services) { throw new IllegalStateException("Unable to delete " + module + ":" + instance + " , ServiceInstance not found"); } @Override - void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on) { + void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on, Services services) { try { ta.destroyModule(on); logger.debug("ServiceInstance {} deleted successfully", on); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java index 1fca16433a..1bb1d9bfba 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java @@ -26,6 +26,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; @@ -36,6 +37,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import javax.management.InstanceNotFoundException; import javax.management.ObjectName; import java.util.HashMap; import java.util.Map; @@ -61,6 +63,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { @VisibleForTesting Element getResponseInternal(final Document document, final EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException { + if (editConfigExecution.shouldTest()) { executeTests(configRegistryClient, editConfigExecution); } @@ -91,7 +94,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { private void executeTests(ConfigRegistryClient configRegistryClient, EditConfigExecution editConfigExecution) throws NetconfDocumentedException { try { - test(configRegistryClient, editConfigExecution.getResolvedXmlElements(), editConfigExecution.getDefaultStrategy()); + test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy()); } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) { logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e); final Map errorInfo = new HashMap<>(); @@ -103,7 +106,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { } private void test(ConfigRegistryClient configRegistryClient, - Map> resolvedModules, EditStrategyType editStrategyType) { + EditConfigExecution execution, EditStrategyType editStrategyType) { ObjectName taON = transactionProvider.getTestTransaction(); try { @@ -111,7 +114,9 @@ public class EditConfig extends AbstractConfigNetconfOperation { if (editStrategyType == EditStrategyType.replace) { transactionProvider.wipeTestTransaction(taON); } - setOnTransaction(configRegistryClient, resolvedModules, taON); + + setOnTransaction(configRegistryClient, execution.getResolvedXmlElements(), execution.getServices(), taON); + // TODO add service reference persistance testing here transactionProvider.validateTestTransaction(taON); } finally { transactionProvider.abortTestTransaction(taON); @@ -126,11 +131,45 @@ public class EditConfig extends AbstractConfigNetconfOperation { if (editConfigExecution.getDefaultStrategy() == EditStrategyType.replace) { transactionProvider.wipeTransaction(); } - setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), taON); + + setOnTransaction(configRegistryClient, editConfigExecution.getResolvedXmlElements(), + editConfigExecution.getServices(), taON); + setServicesOnTransaction(configRegistryClient, editConfigExecution.getServices(), taON); + } + + private void setServicesOnTransaction(ConfigRegistryClient configRegistryClient, Services services, + ObjectName taON) { + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON); + + Map>> namespaceToServiceNameToRefNameToInstance = services + .getNamespaceToServiceNameToRefNameToInstance(); + + for (String serviceNamespace : namespaceToServiceNameToRefNameToInstance.keySet()) { + for (String serviceName : namespaceToServiceNameToRefNameToInstance.get(serviceNamespace).keySet()) { + + String qnameOfService = getQname(ta, serviceNamespace, serviceName); + Map refNameToInstance = namespaceToServiceNameToRefNameToInstance + .get(serviceNamespace).get(serviceName); + + for (String refName : refNameToInstance.keySet()) { + ObjectName on = refNameToInstance.get(refName).getObjectName(ta.getTransactionName()); + // TODO check for duplicates + try { + ta.saveServiceReference(qnameOfService, refName, on); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Unable to save ref name " + refName + " for instance " + on, e); + } + } + } + } + } + + private String getQname(ConfigTransactionClient ta, String namespace, String serviceName) { + return ta.getServiceInterfaceName(namespace, serviceName); } private void setOnTransaction(ConfigRegistryClient configRegistryClient, - Map> resolvedXmlElements, ObjectName taON) { + Map> resolvedXmlElements, Services services, ObjectName taON) { ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON); for (Multimap modulesToResolved : resolvedXmlElements.values()) { @@ -142,7 +181,7 @@ public class EditConfig extends AbstractConfigNetconfOperation { InstanceConfigElementResolved ice = moduleElementResolved.getInstanceConfigElementResolved(); EditConfigStrategy strategy = ice.getEditStrategy(); - strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta); + strategy.executeConfiguration(moduleName, instanceName, ice.getConfiguration(), ta, services); } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java index 6b7b622d56..23166e8cca 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java @@ -10,12 +10,13 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import java.util.Map; public interface EditConfigStrategy { void executeConfiguration(String module, String instance, Map configuration, - ConfigTransactionClient ta); + ConfigTransactionClient ta, Services services); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java index 3d4e5b6d0c..81327133b8 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java @@ -12,10 +12,13 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Multimap; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.util.ConfigRegistryClient; +import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -25,9 +28,7 @@ import org.slf4j.LoggerFactory; import javax.management.ObjectName; import java.util.Arrays; -import java.util.Collections; import java.util.Map; -import java.util.Set; public class EditConfigXmlParser { @@ -47,6 +48,8 @@ public class EditConfigXmlParser { TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient) throws NetconfDocumentedException { + //TODO remove transactionProvider and CfgRegistry from parameters, accept only service ref store + EditStrategyType editStrategyType = EditStrategyType.getDefaultStrategy(); xml.checkName(EditConfigXmlParser.EDIT_CONFIG); @@ -92,21 +95,14 @@ public class EditConfigXmlParser { logger.trace("Setting merge strategy to {}", mergeStrategyString); editStrategyType = EditStrategyType.valueOf(mergeStrategyString); } - Set instancesForFillingServiceRefMapping = Collections.emptySet(); - if (editStrategyType == EditStrategyType.merge) { - instancesForFillingServiceRefMapping = Datastore.getInstanceQueryStrategy(targetDatastore, transactionProvider) - .queryInstances(configRegistryClient); - logger.trace("Pre-filling services from following instances: {}", instancesForFillingServiceRefMapping); - } XmlElement configElement = xml.getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CONFIG_KEY); - return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption, - instancesForFillingServiceRefMapping, editStrategyType); - } + ObjectName taON = transactionProvider.getOrCreateTransaction(); + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON); - private void removeMountpointsFromConfig(XmlElement configElement, XmlElement mountpointsElement) { - configElement.getDomElement().removeChild(mountpointsElement.getDomElement()); + return new EditConfigXmlParser.EditConfigExecution(cfgMapping, configElement, testOption, + ta, editStrategyType); } @VisibleForTesting @@ -135,15 +131,16 @@ public class EditConfigXmlParser { @VisibleForTesting static class EditConfigExecution { - private final XmlElement editConfigXml; + private final Map> resolvedXmlElements; private final TestOption testOption; private final EditStrategyType defaultEditStrategyType; + private final Services services; - EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set instancesForFillingServiceRefMapping, - EditStrategyType defaultStrategy) { - this.editConfigXml = xml; - this.resolvedXmlElements = configResolver.fromXml(configElement, instancesForFillingServiceRefMapping, defaultStrategy); + EditConfigExecution(Config configResolver, XmlElement configElement, TestOption testOption, ServiceReferenceReadableRegistry ta, EditStrategyType defaultStrategy) { + Config.ConfigElementResolved configElementResolved = configResolver.fromXml(configElement, defaultStrategy, ta); + this.resolvedXmlElements = configElementResolved.getResolvedModules(); + this.services = configElementResolved.getServices(); this.testOption = testOption; this.defaultEditStrategyType = defaultStrategy; } @@ -163,5 +160,9 @@ public class EditConfigXmlParser { EditStrategyType getDefaultStrategy() { return defaultEditStrategyType; } + + Services getServices() { + return services; + } } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java index cb03342a1e..676467553b 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; +import com.google.common.collect.Multimap; + import java.util.EnumSet; import java.util.Set; @@ -40,14 +42,14 @@ public enum EditStrategyType { } } - public EditConfigStrategy getFittingStrategy() { + public EditConfigStrategy getFittingStrategy(Multimap providedServices) { switch (this) { case merge: - return new MergeEditConfigStrategy(); + return new MergeEditConfigStrategy(providedServices); case replace: - return new ReplaceEditConfigStrategy(); + return new ReplaceEditConfigStrategy(providedServices); case delete: - return new DeleteEditConfigStrategy(); + return new DeleteEditConfigStrategy(providedServices); case remove: return new RemoveEditConfigStrategy(); case none: diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java index 2a4a784a8a..06befb0565 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java @@ -8,37 +8,67 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; -import java.util.Map.Entry; - -import javax.management.Attribute; -import javax.management.InstanceAlreadyExistsException; -import javax.management.ObjectName; - +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.Attribute; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; +import java.util.Map.Entry; + public class MergeEditConfigStrategy extends AbstractEditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(MergeEditConfigStrategy.class); + private final Multimap providedServices; + + public MergeEditConfigStrategy() { + this.providedServices = HashMultimap.create(); + } + + public MergeEditConfigStrategy(Multimap providedServices) { + this.providedServices = providedServices; + } @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { - ObjectName on; + String module, String instance, Services services) { + ObjectName on = null; try { on = ta.createModule(module, instance); logger.info("New instance for {} {} created under name {}", module, instance, on); - executeStrategy(configuration, ta, on); + addRefNames(services, providedServices, module, instance, ta, on); + executeStrategy(configuration, ta, on, services); } catch (InstanceAlreadyExistsException e1) { throw new IllegalStateException("Unable to create instance for " + module + " : " + instance); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Unable to save default ref name for instance " + on, e); + } + } + + private void addRefNames(Services services, Multimap providedServices, String module, + String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException { + for (Entry namespaceToService : providedServices.entries()) { + + if(services.hasRefName(namespaceToService.getKey(), + namespaceToService.getValue(), on)) + continue; + + String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(), + module, instance); + ta.saveServiceReference( + ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on); } } @Override - void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on) { + void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on, Services services) { for (Entry configAttributeEntry : configuration.entrySet()) { try { AttributeConfigElement ace = configAttributeEntry.getValue(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java index db11ce381e..8347c6b88e 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java @@ -12,6 +12,7 @@ import java.util.Map; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +22,7 @@ public class NoneEditConfigStrategy implements EditConfigStrategy { @Override public void executeConfiguration(String module, String instance, Map configuration, - ConfigTransactionClient ta) { + ConfigTransactionClient ta, Services services) { logger.debug("Skipping configuration element for {}:{}", module, instance); } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java index 76ca09433a..64f082da40 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ed import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +22,7 @@ public class RemoveEditConfigStrategy extends DeleteEditConfigStrategy { @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { + String module, String instance, Services services) { logger.warn("Unable to delete {}:{}, ServiceInstance not found", module, instance); } } diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java index 0091d6cc84..43d852e76a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java @@ -8,37 +8,68 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig; -import java.util.Map; -import java.util.Map.Entry; - -import javax.management.Attribute; -import javax.management.InstanceAlreadyExistsException; -import javax.management.ObjectName; - +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.management.Attribute; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectName; +import java.util.Map; +import java.util.Map.Entry; + public class ReplaceEditConfigStrategy extends AbstractEditConfigStrategy { private static final Logger logger = LoggerFactory.getLogger(ReplaceEditConfigStrategy.class); + private final Multimap providedServices; + + public ReplaceEditConfigStrategy() { + this.providedServices = HashMultimap.create(); + } + + public ReplaceEditConfigStrategy(Multimap providedServices) { + this.providedServices = providedServices; + } + @Override void handleMissingInstance(Map configuration, ConfigTransactionClient ta, - String module, String instance) { + String module, String instance, Services services) { + ObjectName on = null; try { - ObjectName on = ta.createModule(module, instance); + on = ta.createModule(module, instance); logger.debug("New instance for {} {} created under name {}", module, instance, on); - executeStrategy(configuration, ta, on); + addRefNames(services, providedServices, module, instance, ta, on); + executeStrategy(configuration, ta, on, services); } catch (InstanceAlreadyExistsException e) { logger.warn("Error creating instance {}:{}, replace failed", module, instance, e); throw new IllegalStateException("Unable to create new instance for " + module + " : " + instance, e); + } catch (InstanceNotFoundException e) { + throw new IllegalStateException("Unable to save default ref name for instance " + on, e); } } + private void addRefNames(Services services, Multimap providedServices, String module, + String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException { + for (Entry namespaceToService : providedServices.entries()) { + + if(services.hasRefName(namespaceToService.getKey(), + namespaceToService.getValue(), on)) + continue; + + String refName = services.getNewDefaultRefName(namespaceToService.getKey(), namespaceToService.getValue(), + module, instance); + ta.saveServiceReference( + ta.getServiceInterfaceName(namespaceToService.getKey(), namespaceToService.getValue()), refName, on); + } + } @Override - void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on) { + void executeStrategy(Map configuration, ConfigTransactionClient ta, ObjectName on, Services services) { for (Entry configAttributeEntry : configuration.entrySet()) { try { AttributeConfigElement ace = configAttributeEntry.getValue(); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java index 7ee13aeb58..efe4f7dde9 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ge import com.google.common.collect.Maps; import org.opendaylight.controller.config.util.ConfigRegistryClient; +import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry; @@ -25,6 +26,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtim import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore; import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig; +import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.slf4j.Logger; @@ -42,11 +44,13 @@ public class Get extends AbstractConfigNetconfOperation { private final YangStoreSnapshot yangStoreSnapshot; private static final Logger logger = LoggerFactory.getLogger(Get.class); + private final TransactionProvider transactionProvider; public Get(YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient, - String netconfSessionIdForReporting) { + String netconfSessionIdForReporting, TransactionProvider transactionProvider) { super(configRegistryClient, netconfSessionIdForReporting); this.yangStoreSnapshot = yangStoreSnapshot; + this.transactionProvider = transactionProvider; } private Map> createModuleRuntimes(ConfigRegistryClient configRegistryClient, @@ -144,7 +148,9 @@ public class Get extends AbstractConfigNetconfOperation { final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs); - final Element element = runtime.toXml(runtimeBeans, configBeans, document); + ObjectName txOn = transactionProvider.getOrCreateTransaction(); + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(txOn); + final Element element = runtime.toXml(runtimeBeans, configBeans, document, ta); logger.info("{} operation successful", XmlNetconfConstants.GET); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java index f2dfc7079c..d75cfd5d6f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ge import com.google.common.base.Optional; import com.google.common.collect.Maps; import org.opendaylight.controller.config.util.ConfigRegistryClient; +import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; @@ -20,6 +21,7 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorT import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation; import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; @@ -83,7 +85,13 @@ public class GetConfig extends AbstractConfigNetconfOperation { final Config configMapping = new Config(transform(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap())); - dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement); + + + ObjectName on = transactionProvider.getOrCreateTransaction(); + ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(on); + + Services serviceTracker = new Services(ta); + dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker); logger.info("{} operation successful", GET_CONFIG); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java index ec1915d6fc..77c58501cd 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java @@ -56,7 +56,7 @@ final class NetconfOperationProvider { ops.add(new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient, netconfSessionIdForReporting)); ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting)); - ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting)); + ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting, transactionProvider)); ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting)); ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting)); ops.add(new RuntimeRpc(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting)); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java index b8113a0903..0fa005e04a 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java @@ -137,13 +137,14 @@ public class TransactionProvider implements AutoCloseable { } /** - * Wiping means removing all module instances keeping the transaction open. + * Wiping means removing all module instances keeping the transaction open + service references. */ synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) { ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON); Set lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans() : transactionClient.lookupConfigBeans(moduleName); + int i = lookupConfigBeans.size(); for (ObjectName instance : lookupConfigBeans) { try { transactionClient.destroyModule(instance); @@ -156,7 +157,10 @@ public class TransactionProvider implements AutoCloseable { throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e); } } - logger.debug("Transaction {} wiped clean", taON); + logger.debug("Transaction {} wiped clean of {} config beans", taON, i); + + transactionClient.removeAllServiceReferences(); + logger.debug("Transaction {} wiped clean of all service references", taON); } public void wipeTransaction() { diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java index f8916ecac2..ccb793149c 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java @@ -12,12 +12,15 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.matchers.JUnitMatchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface; +import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation; import org.opendaylight.controller.config.manager.impl.AbstractConfigTest; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; @@ -55,15 +58,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; import javax.management.ObjectName; import javax.xml.parsers.ParserConfigurationException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -82,7 +88,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; public class NetconfMappingTest extends AbstractConfigTest { private static final Logger logger = LoggerFactory.getLogger(NetconfMappingTest.class); - private static final String INSTANCE_NAME = "test1"; + private static final String INSTANCE_NAME = "instance-from-code"; private static final String NETCONF_SESSION_ID = "foo"; private NetconfTestImplModuleFactory factory; private DepTestImplModuleFactory factory2; @@ -105,24 +111,99 @@ public class NetconfMappingTest extends AbstractConfigTest { transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID); } - private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException { + private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException { final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction(); final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName); final NetconfTestImplModuleMXBean mxBean = transaction.newMXBeanProxy(on, NetconfTestImplModuleMXBean.class); - setModule(mxBean, transaction); + setModule(mxBean, transaction, instanceName + "_dep"); + int i = 1; + for (Class sInterface : factory.getImplementedServiceIntefaces()) { + ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class); + transaction.saveServiceReference( + transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + instanceName + "_" + i++, + on); + + } transaction.commit(); return on; } + @Test + public void testServicePersistance() throws Exception { + createModule(INSTANCE_NAME); + + edit("netconfMessages/editConfig.xml"); + Element config = getConfigCandidate(); + assertCorrectServiceNames(config, 6, "ref_test2", "user_to_instance_from_code", "ref_dep_user", + "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1", + "ref_from_code_to_instance-from-code_1"); + + edit("netconfMessages/editConfig_addServiceName.xml"); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user", + "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1", + "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"); + + commit(); + config = getConfigRunning(); + assertCorrectRefNamesForDependencies(config); + assertCorrectServiceNames(config, 7, "ref_test2", "user_to_instance_from_code", "ref_dep_user", + "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1", + "ref_from_code_to_instance-from-code_1", "ref_dep_user_another"); + + edit("netconfMessages/editConfig_replace_default.xml"); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 2, "ref_dep", "ref_dep2"); + + edit("netconfMessages/editConfig_remove.xml"); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 0); + + commit(); + config = getConfigCandidate(); + assertCorrectServiceNames(config, 0); + + } + + private void assertCorrectRefNamesForDependencies(Element config) { + NodeList modulesList = config.getElementsByTagName("modules"); + assertEquals(1, modulesList.getLength()); + + Element modules = (Element) modulesList.item(0); + + String trimmedModules = XmlUtil.toString(modules).replaceAll("\\s", ""); + int defaultRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep2"); + int userRefNameCount = StringUtils.countMatches(trimmedModules, "ref_dep_user_two"); + + assertEquals(0, defaultRefNameCount); + assertEquals(2, userRefNameCount); + } + + private void assertCorrectServiceNames(Element configCandidate, int servicesSize, String... refNames) { + NodeList elements = configCandidate.getElementsByTagName("provider"); + assertEquals(servicesSize, elements.getLength()); + + NodeList servicesList = configCandidate.getElementsByTagName("services"); + assertEquals(1, servicesList.getLength()); + + Element services = (Element) servicesList.item(0); + String trimmedServices = XmlUtil.toString(services).replaceAll("\\s", ""); + + for (String s : refNames) { + assertThat(trimmedServices, JUnitMatchers.containsString(s)); + } + } + @Test public void testConfigNetconf() throws Exception { createModule(INSTANCE_NAME); edit("netconfMessages/editConfig.xml"); - checkBinaryLeafEdited(getConfigCandidate()); + Element configCandidate = getConfigCandidate(); + checkBinaryLeafEdited(configCandidate); // default-operation:none, should not affect binary leaf @@ -205,6 +286,7 @@ public class NetconfMappingTest extends AbstractConfigTest { return executeOp(getConfigOp, "netconfMessages/getConfig.xml"); } + @Ignore("second edit message corrupted") @Test(expected = NetconfDocumentedException.class) public void testConfigNetconfReplaceDefaultEx() throws Exception { @@ -394,7 +476,7 @@ public class NetconfMappingTest extends AbstractConfigTest { for (XmlElement moduleElement : modulesElement.getChildElements("module")) { String name = moduleElement.getOnlyChildElement("name").getTextContent(); - if(name.equals("test1")) { + if(name.equals(INSTANCE_NAME)) { XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName); assertEquals(enumContent, enumAttr.getTextContent()); @@ -424,7 +506,8 @@ public class NetconfMappingTest extends AbstractConfigTest { } } - assertEquals("configAttributeType", configAttributeType.getTextContent()); + // TODO verify if should be default value + assertEquals("default-string", configAttributeType.getTextContent()); } private Map> getMbes() throws Exception { @@ -480,7 +563,7 @@ public class NetconfMappingTest extends AbstractConfigTest { } private Element get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException { - Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID); + Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID, transactionProvider); return executeOp(getOp, "netconfMessages/get.xml"); } @@ -516,8 +599,8 @@ public class NetconfMappingTest extends AbstractConfigTest { return Lists.newArrayList(yangDependencies); } - private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction) - throws InstanceAlreadyExistsException { + private void setModule(final NetconfTestImplModuleMXBean mxBean, final ConfigTransactionJMXClient transaction, String depName) + throws InstanceAlreadyExistsException, InstanceNotFoundException { mxBean.setSimpleInt((long) 44); mxBean.setBinaryLeaf(new byte[] { 8, 7, 9 }); final DtoD dtob = getDtoD(); @@ -547,7 +630,15 @@ public class NetconfMappingTest extends AbstractConfigTest { mxBean.setComplexList(Lists. newArrayList()); mxBean.setSimpleList(Lists. newArrayList()); - final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), "dep"); + final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), depName); + int i = 1; + for (Class sInterface : factory2.getImplementedServiceIntefaces()) { + ServiceInterfaceAnnotation annotation = sInterface.getAnnotation(ServiceInterfaceAnnotation.class); + transaction.saveServiceReference( + transaction.getServiceInterfaceName(annotation.namespace(), annotation.localName()), "ref_from_code_to_" + depName + "_" + i++, + testingDepOn); + + } mxBean.setTestingDep(testingDepOn); } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java index 425ecf6d02..d5ba976ccf 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java @@ -13,7 +13,6 @@ import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services.ServiceInstance; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; public class ServiceTrackerTest { @@ -28,44 +27,4 @@ public class ServiceTrackerTest { assertEquals(serviceInstance, serviceInstance2); } - @Test - public void testOneInstanceMultipleServices() { - Services services = new Services(); - services.addServiceEntry("nm", "s1", "module", "instance"); - assertEquals(1, services.getMappedServices().size()); - - services.addServiceEntry("nm2", "s2", "module", "instance"); - assertEquals(2, services.getMappedServices().size()); - } - - @Test - public void testMultipleInstancesOneName() throws Exception { - Services services = new Services(); - services.addServiceEntry("nm", "s1", "module", "instance"); - assertEquals(1, services.getMappedServices().size()); - - services.addServiceEntry("nm", "s1", "module2", "instance"); - assertEquals(1, services.getMappedServices().size()); - assertEquals(2, services.getMappedServices().get("nm").get("s1").size()); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance")); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1")); - } - - @Test - public void testMultipleInstancesOneName2() throws Exception { - Services services = new Services(); - services.addServiceEntry("nm", "s1", "module", "instance_1"); - - services.addServiceEntry("nm2", "s2", "module2", "instance"); - services.addServiceEntry("nm2", "s2", "module3", "instance"); - services.addServiceEntry("nm", "s1", "module3", "instance"); - - assertEquals(2, services.getMappedServices().get("nm").get("s1").size()); - assertEquals(2, services.getMappedServices().get("nm2").get("s2").size()); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_2")); - assertTrue(services.getMappedServices().get("nm").get("s1").containsKey("ref_instance_1")); - assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance")); - assertTrue(services.getMappedServices().get("nm2").get("s2").containsKey("ref_instance_2")); - } - } diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java index 1b8e24702a..6e7a225f38 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java @@ -16,24 +16,23 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; import org.opendaylight.controller.config.util.ConfigRegistryClient; import org.opendaylight.controller.config.util.ConfigTransactionClient; import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement; -import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved; import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services; import org.opendaylight.controller.netconf.confignetconfconnector.operations.ValidateTest; import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser.EditConfigExecution; import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider; -import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import javax.management.ObjectName; import java.util.Collections; import java.util.Map; -import java.util.Set; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyMap; @@ -82,18 +81,11 @@ public class EditConfigTest { EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry, ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING); EditConfigStrategy editStrat = mock(EditConfigStrategy.class); - doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(), - any(ConfigTransactionClient.class)); - Map> resolvedXmlElements = getMapping(editStrat); - Config cfg = mock(Config.class); - XmlElement xmlElement = mock(XmlElement.class); - Set instancesForFillingServiceRefMapping = Collections.emptySet(); - EditStrategyType defaultStrategy = EditStrategyType.getDefaultStrategy(); - doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement, instancesForFillingServiceRefMapping, defaultStrategy); + doNothing().when(editStrat).executeConfiguration(anyString(), anyString(), anyMap(), + any(ConfigTransactionClient.class), any(Services.class)); - EditConfigExecution editConfigExecution = new EditConfigExecution(null, cfg, xmlElement, - EditConfigXmlParser.TestOption.testThenSet, instancesForFillingServiceRefMapping, defaultStrategy); + EditConfigExecution editConfigExecution = mockExecution(editStrat); edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution); @@ -105,7 +97,31 @@ public class EditConfigTest { // For every instance execute strat verify(editStrat, times(2/* Test */+ 2/* Set */)).executeConfiguration(anyString(), anyString(), anyMap(), - any(ConfigTransactionClient.class)); + any(ConfigTransactionClient.class), any(Services.class)); + } + + private EditConfigExecution mockExecution(EditConfigStrategy editStrat) { + EditConfigExecution mock = mock(EditConfigExecution.class); + doReturn(getMapping(editStrat)).when(mock).getResolvedXmlElements(); + doReturn(EditStrategyType.merge).when(mock).getDefaultStrategy(); + doReturn(true).when(mock).shouldSet(); + doReturn(true).when(mock).shouldTest(); + doReturn(mockServices()).when(mock).getServices(); + return mock; + } + + private static ServiceReferenceReadableRegistry mockServiceRegistry() { + ServiceReferenceReadableRegistry mock = mock(ServiceReferenceReadableRegistry.class); + doReturn( + Collections.emptyMap()) + .when(mock).getServiceMapping(); + doReturn("mockedServiceReg").when(mock).toString(); + + return mock; + } + + static Services mockServices() { + return new Services(mockServiceRegistry()); } private Map> getMapping(EditConfigStrategy editStrat) { diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java index 704da6dc0d..78a2043e20 100644 --- a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java +++ b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java @@ -48,7 +48,7 @@ public class ReplaceEditConfigStrategyTest { doReturn(Sets.newHashSet(mockON(), mockON())).when(ta).lookupConfigBeans(); - strat.executeConfiguration("m1", "i1", map, ta); + strat.executeConfiguration("m1", "i1", map, ta, EditConfigTest.mockServices()); verify(ta).lookupConfigBean(anyString(), anyString()); verify(ta).setAttribute(any(ObjectName.class), anyString(), any(Attribute.class)); diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml index 94b73f4b10..35cf2c6a14 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml @@ -11,7 +11,7 @@ - dep + instance-from-code_dep test-impl:impl-dep @@ -29,7 +29,7 @@ test-impl:impl-netconf - test1 + instance-from-code 2.58 @@ -91,16 +91,16 @@ prefix:testing - ref_dep + ref_dep_user prefix:testing - ref_dep + ref_dep_user prefix:testing - ref_dep_2 + ref_dep_user_two @@ -113,7 +113,7 @@ prefix:testing - ref_dep_2 + ref_dep_user_two @@ -122,19 +122,19 @@ prefix:testing - ref_dep - /modules/module[type='impl-dep'][name='dep'] + ref_dep_user + /modules/module[type='impl-dep'][name='instance-from-code_dep'] - ref_dep_2 + ref_dep_user_two /config/modules/module[name='impl-dep']/instance[name='dep2'] - ref_test1 + user_to_instance_from_code - /modules/module[type='impl-netconf'][name='test1'] + /modules/module[type='impl-netconf'][name='instance-from-code'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml new file mode 100644 index 0000000000..30be98e6b5 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml @@ -0,0 +1,34 @@ + + + + + + + set + + merge + + + + + instance-from-code_dep + + test-impl:impl-dep + + + + + + + + prefix:testing + + ref_dep_user_another + /modules/module[type='impl-dep'][name='instance-from-code_dep'] + + + + + + + diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml index ad7c84f3c9..25976707d4 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml @@ -1,4 +1,4 @@ - + @@ -22,6 +22,16 @@ + + + prefix:threadfactory + + user_to_instance_from_code + + /modules/module[type='threadfactory-naming'][name='threadfactory-naming-instance'] + + + diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml index b48730d3f7..a7f1c86391 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml @@ -8,7 +8,7 @@ - dep + instance-from-code_dep test-impl:impl-dep @@ -21,6 +21,7 @@ + test-impl:impl-netconf @@ -66,42 +67,16 @@ 456 44 - - prefix:testing - ref_dep - test-impl:impl-netconf test2 - - prefix:testing - ref_dep - + - - prefix:testing - - ref_dep - /modules/module[type='impl-dep'][name='dep'] - - - - ref_dep_2 - /modules/module[type='impl-dep'][name='dep2'] - - - - ref_test1 - - /modules/module[type='impl-netconf'][name='test1'] - - - diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml index 9d06d98f1c..e07f18cb51 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml @@ -6,6 +6,15 @@ none + + instance-from-code_dep + + test-impl:impl-dep + + + + dep @@ -27,7 +36,7 @@ test-impl:impl-netconf - test1 + instance-from-code - /modules/module[type='impl-netconf' and name='test1'] + /modules/module[type='impl-netconf' and name='instance-from-code'] testarg1 diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml index 3d5117e3bd..da9afd7bf1 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml @@ -1,7 +1,7 @@ - /modules/module[name='test1'][type='impl-netconf']/inner-running-data-additional[key='1'] + /modules/module[name='instance-from-code'][type='impl-netconf']/inner-running-data-additional[key='1'] diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml index 4ba0349f9b..a5b83e6db6 100644 --- a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml +++ b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml @@ -2,7 +2,7 @@ - /modules/module[type='impl-netconf'][name='test1']/inner-running-data[key='0']/inner-inner-running-data[key='1'] + /modules/module[type='impl-netconf'][name='instance-from-code']/inner-running-data[key='0']/inner-inner-running-data[key='1'] -- 2.36.6