Added support for persistance of service references to netconf. 20/3620/2
authorMaros Marsalek <mmarsale@cisco.com>
Mon, 9 Dec 2013 13:31:53 +0000 (14:31 +0100)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 11 Dec 2013 10:51:17 +0000 (10:51 +0000)
Created reference names under services/ subtree are now persisted and available for further edit-config operations.

Change-Id: I366eaab457e9264d266e16eb4e1a1ad8d97d33bc
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
35 files changed:
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributesConstants.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectNameAttributeMappingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectNameAttributeResolvingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfigElementResolved.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/AbstractEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/DeleteEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigXmlParser.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditStrategyType.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/NoneEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/RemoveEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/ServiceTrackerTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/ReplaceEditConfigStrategyTest.java
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_addServiceName.xml [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_threadfactory.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_remove.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.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 (file)
index 0000000..4f9e1fe
--- /dev/null
@@ -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";
+}
index f4d88c7c8e371e0bbc8fd8614c76b79bc69a7a50..842634163607315bd018d00d43c29b1db2dd83d0 100644 (file)
@@ -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.<String> absent())
+                : tracker.getRefName(namespace, serviceName, on, Optional.of(expectedRefName));
 
         return Optional.of(new MappedDependency(namespace, serviceName, refName));
     }
index c6f306b3605cdc83652efd36e53cca6bb9b9f446..d8f0e2357ea0fb57063121b2758aca908b553eb5 100644 (file)
@@ -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);
     }
index f33a32271fd189dd39a61b7403069d765e4d1615..3a5fa1170fec28922155e8e7b2748eb7393448b5 100644 (file)
@@ -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<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
-                                                                                Services serviceTracker, Map<String, Map<String, ModuleConfig>> configs) {
+                                                                                Map<String, Map<String, ModuleConfig>> configs) {
         Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
 
         Map<String, Map<String, Collection<ObjectName>>> 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<ObjectName> instances,
-            Multimap<String, String> providedServices) {
-        for (ObjectName instanceOn : instances) {
-            for (Entry<String, String> serviceName : providedServices.entries()) {
-                serviceTracker.addServiceEntry(serviceName.getKey(), serviceName.getValue(), instanceOn);
-            }
-        }
-    }
-
     private static Multimap<String, ObjectName> mapInstancesToModules(Set<ObjectName> instancesToMap) {
         Multimap<String, ObjectName> retVal = HashMultimap.create();
 
@@ -114,11 +99,10 @@ public class Config {
     // }
 
     public Element toXml(Set<ObjectName> instancesToMap, Optional<String> maybeNamespace, Document document,
-            Element dataElement) {
-        Services serviceTracker = new Services();
+            Element dataElement, Services serviceTracker) {
 
         Map<String, Map<String, Collection<ObjectName>>> 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<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml, Set<ObjectName> instancesForFillingServiceRefMapping,
-                                                                        EditStrategyType defaultEditStrategyType) {
+    public ConfigElementResolved fromXml(XmlElement xml,
+                                         EditStrategyType defaultEditStrategyType, ServiceReferenceReadableRegistry taClient) {
         Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
 
         List<XmlElement> recognisedChildren = Lists.newArrayList();
 
-        Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping);
+        Services serviceTracker = fromXmlServices(xml, recognisedChildren, taClient);
         List<XmlElement> 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<String, Multimap<String, ModuleElementResolved>> resolvedModules;
+        private final Services services;
+
+        public ConfigElementResolved(Map<String, Multimap<String, ModuleElementResolved>> retVal, Services serviceTracker) {
+            this.resolvedModules = retVal;
+            this.services = serviceTracker;
+        }
+
+        public Map<String, Multimap<String, ModuleElementResolved>> getResolvedModules() {
+            return resolvedModules;
+        }
+
+        public Services getServices() {
+            return services;
+        }
     }
 
     private List<XmlElement> fromXmlModules(XmlElement xml, List<XmlElement> recognisedChildren) {
@@ -224,7 +227,8 @@ public class Config {
         innerMap.put(factoryName, moduleElementResolved);
     }
 
-    private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren, Set<ObjectName> instancesForFillingServiceRefMapping) {
+    private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren,
+                                     ServiceReferenceReadableRegistry taClient) {
         Optional<XmlElement> 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<String> services = ;
-            for (Entry<String, String> serviceName : moduleConfig.getProvidedServices().entries()) {
-
-                services.addServiceEntry(serviceName.getKey(), serviceName.getValue(), existingON);
-            }
-        }
+        Services services = Services.resolveServices(mappedServices, taClient);
 
         return services;
     }
index 33858746cb0f06bdd4d7387ad8141f29a6d23b51..aae1636165c07c6822fbadf10ddfeafad2d28653 100644 (file)
@@ -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<String, String> providedServices) {
         Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
 
         Map<String, AttributeReadingStrategy> 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;
index e4bd9212e90995ae7515026c49815645afe6ff3e..55cb60bed5e7df0268908b160650ecd46101e137 100644 (file)
@@ -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<String, AttributeConfigElement> configuration;
+    private final Multimap<String, String> providedServices;
 
-    public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+    public InstanceConfigElementResolved(String currentStrategy, Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> providedServices) {
         EditStrategyType valueOf = checkStrategy(currentStrategy, defaultStrategy);
         this.editStrategy = valueOf;
         this.configuration = configuration;
+        this.providedServices = providedServices;
     }
 
-    public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy) {
+    public InstanceConfigElementResolved(Map<String, AttributeConfigElement> configuration, EditStrategyType defaultStrategy, Multimap<String, String> 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<String, AttributeConfigElement> getConfiguration() {
index 2e2a26400f19899b3f172e80f0de00f7c46ce1c6..2ac6fe0a9bb650116e5f3591fb35cdf8655ee311 100644 (file)
@@ -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);
     }
 
index f522668733497333b7b2ac2052fe5949985f8f51..a4f5e4999c3fb549c635a5b1295a1323bc3a9fe7 100644 (file)
@@ -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<ServiceInstance, String> instanceToRef = Maps.newHashMap();
     private final Map<String /*Namespace*/, Map<String/* ServiceName */, Map<String/* refName */, ServiceInstance>>> 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<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
 
-        Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
-        if (serviceNameToRefNameToInstance == null) {
-            serviceNameToRefNameToInstance = Maps.newHashMap();
-            namespaceToServiceNameToRefNameToInstance.put(namespace, serviceNameToRefNameToInstance);
-        }
+        Map<String, String> refNameToInstance;
+        if(serviceNameToRefNameToInstance == null || serviceNameToRefNameToInstance.containsKey(serviceName) == false) {
+            refNameToInstance = Collections.emptyMap();
+        } else
+            refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
 
-        Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
-        if (refNameToInstance == null) {
-            refNameToInstance = Maps.newHashMap();
-            serviceNameToRefNameToInstance.put(serviceName, refNameToInstance);
+        final Set<String> 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<String> 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<String> toSet(Collection<String> values) {
@@ -109,15 +89,15 @@ public final class Services {
     }
 
     public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) {
-        Map<String, Map<String, ServiceInstance>> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance.get(namespace);
-        Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace + " , "
-                + serviceNameToRefNameToInstance.keySet());
+        Map<String, Map<String, String>> serviceNameToRefNameToInstance = getMappedServices().get(namespace);
+
+        Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace);
 
-        Map<String, ServiceInstance> refNameToInstance = serviceNameToRefNameToInstance.get(serviceName);
+        Map<String, String> 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<String, String> innerInnerRetVal = Maps.transformValues(
-                        serviceNameToRefNameToInstance.get(serviceName), new Function<ServiceInstance, String>() {
-                            @Nullable
-                            @Override
-                            public String apply(@Nullable ServiceInstance serviceInstance) {
-                                return serviceInstance.toString();
-                            }
-                        });
+                Map<String, String> innerInnerRetVal = Maps.newHashMap();
+                for (Entry<String, ServiceInstance> refNameToSi : serviceNameToRefNameToInstance.get(serviceName).entrySet()) {
+                    innerInnerRetVal.put(refNameToSi.getKey(), refNameToSi.getValue().toString());
+                }
                 innerRetVal.put(serviceName, innerInnerRetVal);
             }
             retVal.put(namespace, innerRetVal);
         }
 
+        Map<String, Map<String, ObjectName>> 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<String, Map<String, String>> serviceToRefs = retVal.get(namespace);
+                if(serviceToRefs==null) {
+                    serviceToRefs = Maps.newHashMap();
+                    retVal.put(namespace, serviceToRefs);
+                }
+
+                Map<String, String> 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<String, Map<String, Map<String, ServiceInstance>>> getNamespaceToServiceNameToRefNameToInstance() {
+        return namespaceToServiceNameToRefNameToInstance;
+    }
+
     // TODO hide resolveServices, call it explicitly in fromXml
 
-    public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices) {
-        Services tracker = new Services();
+    public static Services resolveServices(Map<String, Map<String, Map<String, String>>> mappedServices, ServiceReferenceReadableRegistry taClient) {
+        Services tracker = new Services(taClient);
 
         for (Entry<String, Map<String, Map<String, String>>> 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<String, Map<String, Map<String, String>>> fromXml(XmlElement xml) {
         Map<String, Map<String, Map<String, String>>> retVal = Maps.newHashMap();
 
@@ -275,6 +290,51 @@ public final class Services {
         return root;
     }
 
+    public String getRefName(String namespace, String serviceName, ObjectName on, Optional<String> expectedRefName) {
+        Optional<String> 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<String> getRefNameOptional(String namespace, String serviceName, ObjectName on,
+            Optional<String> expectedRefName) {
+        Map<String, Map<String, String>> services = getMappedServices().get(namespace);
+
+        if(services == null) return Optional.absent();
+        Map<String, String> refs = services.get(serviceName);
+
+        if(refs == null) return Optional.absent();
+        Multimap<ServiceInstance, String> reverted = revertMap(refs);
+
+        ServiceInstance serviceInstance = ServiceInstance.fromObjectName(on);
+        Collection<String> 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<ServiceInstance, String> revertMap(Map<String, String> refs) {
+        Multimap<ServiceInstance, String> multimap = HashMultimap.create();
+
+        for (Entry<String, String> 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.<String>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));
+        }
     }
 
 }
index 64f295a4d885f784a1f2c6a0ddaea915bc19ee8e..89c782c51c86e6acda56b426e6d76a70c2bc0c30 100644 (file)
@@ -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<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document) {
-        Services serviceTracker = new Services();
+    public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> 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<String, Multimap<String, ObjectName>> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap);
         Map<String, Map<String, Collection<ObjectName>>> moduleToConfigInstance = Config.getMappedInstances(
-                configBeans, serviceTracker, moduleConfigs);
+                configBeans, moduleConfigs);
 
         for (String localNamespace : moduleConfigs.keySet()) {
 
index d8ea7d7af7ac955b339d629312d84b98a9fdf617..65df965afd1e08167c63f70ba0c56159a085d2db 100644 (file)
@@ -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<String, AttributeConfigElement> 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<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance);
+                                        String module, String instance, Services services);
 
     abstract void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            ObjectName objectName);
+                                  ObjectName objectName, Services services);
 
 }
index ffe107f8ce726953f376e98327be466f80d69437..12beaf8f8e19ff29048cb12c426c372ff047d14c 100644 (file)
@@ -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<String, String> providedServices;
+
+    public DeleteEditConfigStrategy() {
+        this.providedServices = HashMultimap.create();
+    }
+
+    public DeleteEditConfigStrategy(Multimap<String, String> providedServices) {
+        this.providedServices = providedServices;
+    }
+
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> 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<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
         try {
             ta.destroyModule(on);
             logger.debug("ServiceInstance {} deleted successfully", on);
index 1fca16433a9ac7d1e3af41c64c9167138b5afd65..1bb1d9bfba7babf8fa2dc504909e4f89b6730530 100644 (file)
@@ -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<String, String> errorInfo = new HashMap<>();
@@ -103,7 +106,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     private void test(ConfigRegistryClient configRegistryClient,
-                      Map<String, Multimap<String, ModuleElementResolved>> 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<String, Map<String, Map<String, Services.ServiceInstance>>> namespaceToServiceNameToRefNameToInstance = services
+                .getNamespaceToServiceNameToRefNameToInstance();
+
+        for (String serviceNamespace : namespaceToServiceNameToRefNameToInstance.keySet()) {
+            for (String serviceName : namespaceToServiceNameToRefNameToInstance.get(serviceNamespace).keySet()) {
+
+                String qnameOfService = getQname(ta, serviceNamespace, serviceName);
+                Map<String, Services.ServiceInstance> 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<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, ObjectName taON) {
+                                  Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements, Services services, ObjectName taON) {
         ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(taON);
 
         for (Multimap<String, ModuleElementResolved> 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);
             }
         }
     }
index 6b7b622d56cb785370d1a578c8045dbba3f94338..23166e8cca5c6e0d4c6fbc955de83de8db94a6f3 100644 (file)
@@ -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<String, AttributeConfigElement> configuration,
-            ConfigTransactionClient ta);
+                              ConfigTransactionClient ta, Services services);
 
 }
index 3d4e5b6d0c2b9b431ae1d73cae22ea035cb304b6..81327133b82a440c9b7599672134e7b63fd00f49 100644 (file)
@@ -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<ObjectName> 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<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements;
         private final TestOption testOption;
         private final EditStrategyType defaultEditStrategyType;
+        private final Services services;
 
-        EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set<ObjectName> 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;
+        }
     }
 }
index cb03342a1e1febf8d883b1a47ac271ade2c96637..676467553bb61c5c46e380c8b8e33331778ea141 100644 (file)
@@ -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<String, String> 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:
index 2a4a784a8a7bea85a4bcfdc3ee10836d00b5aa1d..06befb0565067592b58465782d66caa74a568100 100644 (file)
@@ -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<String, String> providedServices;
+
+    public MergeEditConfigStrategy() {
+        this.providedServices = HashMultimap.create();
+    }
+
+    public MergeEditConfigStrategy(Multimap<String, String> providedServices) {
+        this.providedServices = providedServices;
+    }
 
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> 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<String, String> providedServices, String module,
+            String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+        for (Entry<String, String> 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<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
         for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
             try {
                 AttributeConfigElement ace = configAttributeEntry.getValue();
index db11ce381eb82db6076189fa092adcffb97ff998..8347c6b88e23325fa579527a5f30785a99216b7d 100644 (file)
@@ -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<String, AttributeConfigElement> configuration,
-            ConfigTransactionClient ta) {
+                                     ConfigTransactionClient ta, Services services) {
         logger.debug("Skipping configuration element for {}:{}", module, instance);
     }
 
index 76ca09433adc8b9b4f98d3508eb586aa16c79b48..64f082da40773b4a6dab473bed7e45722847ffca 100644 (file)
@@ -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<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance) {
+                               String module, String instance, Services services) {
         logger.warn("Unable to delete {}:{}, ServiceInstance not found", module, instance);
     }
 }
index 0091d6cc84ca7a42ed13d08259685dd127fa4d56..43d852e76a32f3b35a8bee016b6ca4ab4f8c6d04 100644 (file)
@@ -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<String, String> providedServices;
+
+    public ReplaceEditConfigStrategy() {
+        this.providedServices = HashMultimap.create();
+    }
+
+    public ReplaceEditConfigStrategy(Multimap<String, String> providedServices) {
+        this.providedServices = providedServices;
+    }
+
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> 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<String, String> providedServices, String module,
+                             String instance, ConfigTransactionClient ta, ObjectName on) throws InstanceNotFoundException {
+        for (Entry<String, String> 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<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on) {
+    void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, Services services) {
         for (Entry<String, AttributeConfigElement> configAttributeEntry : configuration.entrySet()) {
             try {
                 AttributeConfigElement ace = configAttributeEntry.getValue();
index 7ee13aeb589c713351f760464f19a4aff48647d3..efe4f7dde9b483bd488e753a90cee2a335b4de05 100644 (file)
@@ -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<String, Map<String, ModuleRuntime>> 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);
 
index f2dfc7079c869d5f8db32db4550e677bdca8a19f..d75cfd5d6f049d9d586ac856fa0ccd7b70b3c00c 100644 (file)
@@ -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);
 
index ec1915d6fc31aaab6d55aed10ecc95e4d9177613..77c58501cd42942e8bb55793d18408f6a31c3441 100644 (file)
@@ -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));
index b8113a090313d270c4b1a391777d0d6e2e7d759e..0fa005e04a7930df7b1e85fc3aa933da4db98ac4 100644 (file)
@@ -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<ObjectName> 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() {
index f8916ecac2244943b55abe0dd036e0e52204f3f3..ccb793149c4d21162ac11e3495981e4de1898faa 100644 (file)
@@ -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<? extends AbstractServiceInterface> 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<String, Map<String, ModuleMXBeanEntry>> 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.<ComplexList> newArrayList());
         mxBean.setSimpleList(Lists.<Integer> newArrayList());
 
-        final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), "dep");
+        final ObjectName testingDepOn = transaction.createModule(this.factory2.getImplementationName(), depName);
+        int i = 1;
+        for (Class<? extends AbstractServiceInterface> 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);
     }
 
index 425ecf6d02628962de3b8268d21b119c72370bf2..d5ba976ccfd1feabbf5ec97412b09e9f0ce1f8f9 100644 (file)
@@ -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"));
-    }
-
 }
index 1b8e24702aa32300a600518704250b02bdd480c1..6e7a225f38452250ca4803c17ac56a2d2999822f 100644 (file)
@@ -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<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements = getMapping(editStrat);
 
-        Config cfg = mock(Config.class);
-        XmlElement xmlElement = mock(XmlElement.class);
-        Set<ObjectName> 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<String, Multimap<String, ModuleElementResolved>> getMapping(EditConfigStrategy editStrat) {
index 704da6dc0d8d0819923ed67f973c01e3fa3ef045..78a2043e202413786f1000954c10289ce5395696 100644 (file)
@@ -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));
index 94b73f4b100754e17918b9d5d75bed8542130f46..35cf2c6a1423e090a3205376a0c2f953c0fd4b48 100644 (file)
@@ -11,7 +11,7 @@
             <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
 
                 <module>
-                    <name>dep</name>
+                    <name>instance-from-code_dep</name>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-dep
                     </type>
@@ -29,7 +29,7 @@
                         test-impl:impl-netconf
                     </type>
 
-                    <name>test1</name>
+                    <name>instance-from-code</name>
 
                     <sleep-factor>
                         2.58
                     </peers>
                     <testing-dep>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
+                        <name>ref_dep_user</name>
                     </testing-dep>
 
                     <testing-deps>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
+                        <name>ref_dep_user</name>
                     </testing-deps>
                     <testing-deps>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep_2</name>
+                        <name>ref_dep_user_two</name>
                     </testing-deps>
                 </module>
 
 
                     <testing-dep>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep_2</name>
+                        <name>ref_dep_user_two</name>
                     </testing-dep>
                 </module>
             </modules>
                 <service>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
-                        <name>ref_dep</name>
-                        <provider>/modules/module[type='impl-dep'][name='dep']
+                        <name>ref_dep_user</name>
+                        <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
                         </provider>
                     </instance>
                     <instance>
-                        <name>ref_dep_2</name>
+                        <name>ref_dep_user_two</name>
                         <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
                         </provider>
                     </instance>
                     <instance>
-                        <name>ref_test1</name>
+                        <name>user_to_instance_from_code</name>
                         <provider>
-                            /modules/module[type='impl-netconf'][name='test1']
+                            /modules/module[type='impl-netconf'][name='instance-from-code']
                         </provider>
                     </instance>
                 </service>
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 (file)
index 0000000..30be98e
--- /dev/null
@@ -0,0 +1,34 @@
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <candidate/>
+        </target>
+        <test-option>
+            set
+        </test-option>
+        <default-operation>merge</default-operation>
+        <config>
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+                <module>
+                    <name>instance-from-code_dep</name>
+                    <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        test-impl:impl-dep
+                    </type>
+                </module>
+
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+                    <instance>
+                        <name>ref_dep_user_another</name>
+                        <provider>/modules/module[type='impl-dep'][name='instance-from-code_dep']
+                        </provider>
+                    </instance>
+                </service>
+            </services>
+        </config>
+    </edit-config>
+</rpc>
index ad7c84f3c96e46d799923532c70939b7c2a0073a..25976707d4eb1295da0b1d802f218a34426dfedb 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8" ?>
 <rpc message-id="6"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <edit-config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
                     </name-prefix>
                 </module>
             </modules>
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl">prefix:threadfactory</type>
+                    <instance>
+                        <name>user_to_instance_from_code</name>
+                        <provider>
+                            /modules/module[type='threadfactory-naming'][name='threadfactory-naming-instance']</provider>
+                    </instance>
+                </service>
+            </services>
         </config>
     </edit-config>
 </rpc>
index b48730d3f71e74a86fde37131c38602d3f1169c1..a7f1c863910f4b24b421531b82ffb9cb68499452 100644 (file)
@@ -8,7 +8,7 @@
         <config>
             <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
                 <module>
-                    <name>dep</name>
+                    <name>instance-from-code_dep</name>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-dep
                     </type>
@@ -21,6 +21,7 @@
                     </type>
                 </module>
 
+
                 <module>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-netconf
                         <simple-int3>456</simple-int3>
                         <core-size>44</core-size>
                     </peers>
-                    <testing-dep>
-                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
-                    </testing-dep>
                 </module>
                 <module>
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-netconf
                     </type>
                     <name>test2</name>
-                    <testing-dep>
-                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
-                    </testing-dep>
                 </module>
             </modules>
+
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <service>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                    <instance>
-                        <name>ref_dep</name>
-                        <provider>/modules/module[type='impl-dep'][name='dep']
-                        </provider>
-                    </instance>
-                    <instance>
-                        <name>ref_dep_2</name>
-                        <provider>/modules/module[type='impl-dep'][name='dep2']
-                        </provider>
-                    </instance>
-                    <instance>
-                        <name>ref_test1</name>
-                        <provider>
-                            /modules/module[type='impl-netconf'][name='test1']
-                        </provider>
-                    </instance>
-                </service>
             </services>
         </config>
     </edit-config>
index 9d06d98f1c131b2cc405b130288fb6c375851771..e07f18cb5119b3acef99c58e684614ebff2799d7 100644 (file)
@@ -6,6 +6,15 @@
         <default-operation>none</default-operation>
         <config>
             <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
+                        nc:operation="remove">
+                    <name>instance-from-code_dep</name>
+                    <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        test-impl:impl-dep
+                    </type>
+                </module>
+
+
                 <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
                         nc:operation="remove">
                     <name>dep</name>
@@ -27,7 +36,7 @@
                     <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
                         test-impl:impl-netconf
                     </type>
-                    <name>test1</name>
+                    <name>instance-from-code</name>
                 </module>
 
                 <module xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
index 46b833cf68cb3f4ff41442880bfe043575faf63b..5de3de1de223592bac091e830109fdb54820fe18 100644 (file)
@@ -1,6 +1,6 @@
 <rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <no-arg xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
-        <context-instance>/modules/module[type='impl-netconf' and name='test1']</context-instance>
+        <context-instance>/modules/module[type='impl-netconf' and name='instance-from-code']</context-instance>
         <arg1>
             testarg1
         </arg1>
index 3d5117e3bdf15bee2f2b51539dd5435db58874ec..da9afd7bf1e00677313215d81c26fae5af88113b 100644 (file)
@@ -1,7 +1,7 @@
 <rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <noArgInner xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
         <context-instance>
-            /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']
         </context-instance>
     </noArgInner>
 </rpc>
index 4ba0349f9b7d32c2b4532f1c78eccd9d4e71fc99..a5b83e6db6f39a470462ebecda59a37e1de384bb 100644 (file)
@@ -2,7 +2,7 @@
     <leaf-list-output
             xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
         <context-instance>
-            /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']
         </context-instance>
     </leaf-list-output>
 </rpc>