Fix config-netconf-connector needed for interacting with yuma's yangcli. 41/2941/2
authorTomas Olvecky <tolvecky@cisco.com>
Thu, 21 Nov 2013 12:29:09 +0000 (13:29 +0100)
committerTomas Olvecky <tolvecky@cisco.com>
Thu, 21 Nov 2013 13:27:55 +0000 (14:27 +0100)
Mitigate issue when yuma is sending services/service/type with a prefix that is not referenced anywhere - it will be ignored.
When issuing edit-config with merge strategy, populate services as they appear in get-config.

Change-Id: I2c30f3b626fc25cfd3b46225d5f1c24109d655b7
Signed-off-by: Tomas Olvecky <tolvecky@cisco.com>
13 files changed:
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java
opendaylight/config/yang-store-api/src/main/java/org/opendaylight/controller/config/yang/store/api/YangStoreSnapshot.java
opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/ExtenderYangTracker.java
opendaylight/config/yang-store-impl/src/main/java/org/opendaylight/controller/config/yang/store/impl/YangStoreSnapshotImpl.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/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/operations/editconfig/EditConfig.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/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java

index 590081072b422ac1ecc8f973a551439db9aea649..fdc573f9757b1acb2c32162c9f1be757916a3e58 100644 (file)
@@ -129,7 +129,7 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     private final String nullableDescription, packageName, javaNamePrefix,
             namespace;
 
-    private final Map<String, String> providedServices;
+    private final Map<String /* java fully qualified name */, String/* identity local name */> providedServices;
 
     private Collection<RuntimeBeanEntry> runtimeBeans;
 
@@ -180,6 +180,10 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         return packageName;
     }
 
+    /**
+     * @return services implemented by this module. Keys are fully qualified java names of generated
+     * ServiceInterface classes, values are identity local names.
+     */
     public Map<String, String> getProvidedServices() {
         return providedServices;
     }
index 40daf4018aee8e1597391a19ebb763cbd50337e0..da8b5e4ed14a2836cf9bc3edf71daad39af20f14 100644 (file)
@@ -15,7 +15,8 @@ import org.opendaylight.yangtools.yang.model.api.Module;
 
 public interface YangStoreSnapshot extends AutoCloseable {
 
-    Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap();
+    Map<String/* Namespace from yang file */,
+            Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> getModuleMXBeanEntryMap();
 
     Map<String, Entry<Module, String>> getModuleMap();
 
index 90b94ef120c8d2e05473e76db4db7e7dd325c46a..fcdc10f109bca6289b3cc181821970430ffa6066 100644 (file)
@@ -78,7 +78,7 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements YangSt
     }
 
     @Override
-    public Object addingBundle(Bundle bundle, BundleEvent event) {
+    public synchronized Object addingBundle(Bundle bundle, BundleEvent event) {
 
         // Ignore system bundle:
         // system bundle might have config-api on classpath &&
@@ -121,7 +121,7 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements YangSt
         return bundle;
     }
 
-    private void onSnapshotFailure(Bundle bundle, List<URL> addedURLs, Exception failureReason) {
+    private synchronized void onSnapshotFailure(Bundle bundle, List<URL> addedURLs, Exception failureReason) {
         // inconsistent state
         inconsistentBundlesToYangURLs.putAll(bundle, addedURLs);
 
@@ -129,9 +129,10 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements YangSt
                 consistentBundlesToYangURLs, inconsistentBundlesToYangURLs, failureReason);
         logger.warn("Yang store is falling back on last consistent state containing {} files, inconsistent yang files size is {}, reason {}",
                 consistentBundlesToYangURLs.size(), inconsistentBundlesToYangURLs.size(), failureReason.toString());
+        cache.setInconsistentURLsForReporting(inconsistentBundlesToYangURLs.values());
     }
 
-    private void onSnapshotSuccess(Multimap<Bundle, URL> proposedNewState, YangStoreSnapshotImpl snapshot) {
+    private synchronized void onSnapshotSuccess(Multimap<Bundle, URL> proposedNewState, YangStoreSnapshotImpl snapshot) {
         // consistent state
         // merge into
         consistentBundlesToYangURLs.clear();
@@ -139,12 +140,12 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements YangSt
         inconsistentBundlesToYangURLs.clear();
 
         updateCache(snapshot);
-
+        cache.setInconsistentURLsForReporting(Collections.<URL> emptySet());
         logger.info("Yang store updated to new consistent state containing {} yang files", consistentBundlesToYangURLs.size());
         logger.debug("Yang store updated to new consistent state containing {}", consistentBundlesToYangURLs);
     }
 
-    private void updateCache(YangStoreSnapshotImpl snapshot) {
+    private synchronized void updateCache(YangStoreSnapshotImpl snapshot) {
         cache.cacheYangStore(consistentBundlesToYangURLs, snapshot);
     }
 
@@ -213,11 +214,14 @@ public class ExtenderYangTracker extends BundleTracker<Object> implements YangSt
 }
 
 class YangStoreCache {
+    private static final Logger logger = LoggerFactory.getLogger(YangStoreCache.class);
 
     @GuardedBy("this")
     private Set<URL> cachedUrls = null;
     @GuardedBy("this")
     private Optional<YangStoreSnapshot> cachedYangStoreSnapshot = getInitialSnapshot();
+    @GuardedBy("this")
+    private Collection<URL> inconsistentURLsForReporting = Collections.emptySet();
 
     synchronized Optional<YangStoreSnapshot> getSnapshotIfPossible(Multimap<Bundle, URL> bundlesToYangURLs) {
         Set<URL> urls = setFromMultimapValues(bundlesToYangURLs);
@@ -225,6 +229,9 @@ class YangStoreCache {
         if (cachedUrls==null || cachedUrls.equals(urls)) {
             Preconditions.checkState(cachedYangStoreSnapshot.isPresent());
             YangStoreSnapshot freshSnapshot = new YangStoreSnapshotImpl(cachedYangStoreSnapshot.get());
+            if (inconsistentURLsForReporting.size() > 0){
+                logger.warn("Some yang URLs are ignored: {}", inconsistentURLsForReporting);
+            }
             return Optional.of(freshSnapshot);
         }
 
@@ -239,7 +246,7 @@ class YangStoreCache {
     }
 
     synchronized void cacheYangStore(Multimap<Bundle, URL> urls,
-                        YangStoreSnapshot yangStoreSnapshot) {
+                                     YangStoreSnapshot yangStoreSnapshot) {
         this.cachedUrls = setFromMultimapValues(urls);
         this.cachedYangStoreSnapshot = Optional.of(yangStoreSnapshot);
     }
@@ -252,6 +259,10 @@ class YangStoreCache {
         }
     }
 
+    public synchronized void setInconsistentURLsForReporting(Collection<URL> urls){
+        inconsistentURLsForReporting = urls;
+    }
+
     private Optional<YangStoreSnapshot> getInitialSnapshot() {
         YangStoreSnapshot initialSnapshot = new YangStoreSnapshot() {
             @Override
index d5936c28aebfb8b8a9e204ced8e5416590601e5d..ea709e1a45cd9d39d6447b72bc06affe2a744a76 100644 (file)
@@ -34,6 +34,10 @@ public class YangStoreSnapshotImpl implements YangStoreSnapshot {
         this.moduleMap = yangStoreSnapshot.getModuleMap();
     }
 
+    /**
+     * @return all loaded config modules. Key of outer map is namespace of yang file.
+     * Key of inner map is name of module entry. Value is module entry.
+     */
     @Override
     public Map<String, Map<String, ModuleMXBeanEntry>> getModuleMXBeanEntryMap() {
         return moduleMXBeanEntryMap;
index 5469015a2306089a44ab497306969737daf72267..af6e3db8e9406827868cfe214ee498bc2ac0c08c 100644 (file)
@@ -39,8 +39,14 @@ public class ObjectNameAttributeResolvingStrategy extends AbstractAttributeResol
         Util.checkType(value, ObjectNameAttributeMappingStrategy.MappedDependency.class);
 
         ObjectNameAttributeMappingStrategy.MappedDependency mappedDep = (ObjectNameAttributeMappingStrategy.MappedDependency) value;
-        ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(mappedDep.getServiceName(),
-                mappedDep.getRefName());
+        String serviceName = mappedDep.getServiceName();
+        if (serviceName.contains(":")) {
+            // hack for yuma
+            serviceName = serviceName.substring(serviceName.indexOf(":") + 1);
+        }
+        String refName = mappedDep.getRefName();
+        logger.trace("Getting service instance by service name {} and ref name {}", serviceName, refName);
+        ServiceInstance byRefName = serviceTracker.getByServiceAndRefName(serviceName, refName);
         ObjectName on = ObjectNameUtil.createReadOnlyModuleON(byRefName.getModuleName(), byRefName.getInstanceName());
         logger.debug("Attribute {} : {} parsed to type {}", attrName, value, getOpenType());
         return Optional.of(on);
index 8c7621a24b4ad707b293373e7cf596d1b04b8262..ca849c71cf8bcc8ca50b543d9b97a0ac79af2e27 100644 (file)
@@ -8,13 +8,6 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.HashMultimap;
@@ -25,20 +18,37 @@ import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 import javax.management.ObjectName;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.lang.String.format;
 
 public class Config {
+    private final Logger logger = LoggerFactory.getLogger(Config.class);
 
-    private final Map<String, Map<String, ModuleConfig>> moduleConfigs;
+    private final Map<String/* Namespace from yang file */,
+            Map<String /* Name of module entry from yang file */, ModuleConfig>> moduleConfigs;
+    private final Map<String, ModuleConfig> moduleNamesToConfigs;
 
     public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
         this.moduleConfigs = moduleConfigs;
+        Map<String, ModuleConfig> moduleNamesToConfigs = new HashMap<>();
+        for (Entry<String, Map<String, ModuleConfig>> entry : moduleConfigs.entrySet()) {
+            moduleNamesToConfigs.putAll(entry.getValue());
+        }
+        this.moduleNamesToConfigs = Collections.unmodifiableMap(moduleNamesToConfigs);
     }
 
     private Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
@@ -64,7 +74,7 @@ public class Config {
                 // All found instances add to service tracker in advance
                 // This way all instances will be serialized as all available
                 // services when get-config is triggered
-                // (even if they are not used as services by other onstances)
+                // (even if they are not used as services by other instances)
                 // = more user friendly
                 addServices(serviceTracker, instances, mbeEntry.getValue().getProvidedServices());
 
@@ -152,12 +162,12 @@ 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) {
+    public Map<String, Multimap<String, ModuleElementResolved>> fromXml(XmlElement xml, Set<ObjectName> instancesForFillingServiceRefMapping) {
         Map<String, Multimap<String, ModuleElementResolved>> retVal = Maps.newHashMap();
 
         List<XmlElement> recognisedChildren = Lists.newArrayList();
 
-        Services serviceTracker = fromXmlServices(xml, recognisedChildren);
+        Services serviceTracker = fromXmlServices(xml, recognisedChildren, instancesForFillingServiceRefMapping);
         List<XmlElement> moduleElements = fromXmlModules(xml, recognisedChildren);
 
         xml.checkUnrecognisedElements(recognisedChildren);
@@ -208,7 +218,7 @@ public class Config {
         innerMap.put(factoryName, moduleElementResolved);
     }
 
-    private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren) {
+    private Services fromXmlServices(XmlElement xml, List<XmlElement> recognisedChildren, Set<ObjectName> instancesForFillingServiceRefMapping) {
         Optional<XmlElement> servicesElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SERVICES_KEY,
                 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
 
@@ -219,8 +229,23 @@ 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 (String serviceName : moduleConfig.getProvidedServices()) {
+                services.addServiceEntry(serviceName, existingON);
+            }
+        }
 
-        return Services.resolveServices(mappedServices);
+        return services;
     }
 
     private String getFactoryName(String factoryNameWithPrefix, String prefixOrEmptyString) {
index d1ba0b0206b0c44b743302bcba2e3f33fd784947..549d94bdf2774fe1c453a742c01812004ae9bcc8 100644 (file)
@@ -109,17 +109,19 @@ public final class InstanceConfig {
                 depTracker).prepareResolving(yangToAttrConfig);
 
         for (Entry<String, AttributeConfigElement> configDefEntry : mappedConfig.getConfiguration().entrySet()) {
+            AttributeConfigElement value = configDefEntry.getValue();
+            String attributeName = configDefEntry.getKey();
             try {
-
                 AttributeResolvingStrategy<?, ? extends OpenType<?>> attributeResolvingStrategy = resolvingStrategies
-                        .get(configDefEntry.getKey());
+                        .get(attributeName);
+                logger.trace("Trying to set value {} of attribute {} with {}", value, attributeName, attributeResolvingStrategy);
 
-                configDefEntry.getValue().resolveValue(attributeResolvingStrategy, configDefEntry.getKey());
-                configDefEntry.getValue().setJmxName(
-                        yangToAttrConfig.get(configDefEntry.getKey()).getUpperCaseCammelCase());
+                value.resolveValue(attributeResolvingStrategy, attributeName);
+                value.setJmxName(
+                        yangToAttrConfig.get(attributeName).getUpperCaseCammelCase());
             } catch (Exception e) {
-                throw new IllegalStateException("Unable to resolve value " + configDefEntry.getValue()
-                        + " to attribute " + configDefEntry.getKey(), e);
+                throw new IllegalStateException("Unable to resolve value " + value
+                        + " to attribute " + attributeName, e);
             }
         }
     }
index 3a0c54754bdacb4c39ec28be388fbbfdb897d778..264c9c11da0a194f265baa76135051d66c3db8c3 100644 (file)
@@ -17,7 +17,6 @@ import org.w3c.dom.Element;
 
 import javax.management.ObjectName;
 import java.util.Collection;
-import java.util.Collections;
 
 public class ModuleConfig {
 
@@ -31,10 +30,6 @@ public class ModuleConfig {
         this.providedServices = providedServices;
     }
 
-    public ModuleConfig(String key, InstanceConfig instanceConfig) {
-        this(key, instanceConfig, Collections.<String> emptyList());
-    }
-
     public InstanceConfig getMbeanMapping() {
         return instanceConfig;
     }
index 7e4b6c2c06a5040750f1a75510c747fdccead290..883dde7564a8785b6145ccec544390478bb9ffe5 100644 (file)
@@ -8,6 +8,7 @@
 
 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.Preconditions;
 import com.google.common.collect.Maps;
@@ -15,6 +16,8 @@ import com.google.common.collect.Sets;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -29,6 +32,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";
     private static final String NAME_KEY = "name";
@@ -46,9 +50,13 @@ public final class Services {
         String moduleName = on.getKeyProperty("moduleFactoryName");
         String instanceName = on.getKeyProperty("instanceName");
 
-        return addServiceEntry(serviceName, moduleName, instanceName);
+        String refName = addServiceEntry(serviceName, moduleName, instanceName);
+        logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}",
+                serviceName, refName, moduleName, instanceName);
+        return refName;
     }
 
+    @VisibleForTesting
     public String addServiceEntry(String serviceName, String moduleName, String instanceName) {
         ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName);
         serviceInstance.setServiceName(serviceName);
index be3b01db5debfa6897b30ded968627aede84eaa6..d04fdbcc4398a926aca99e374621c00fb6c38510 100644 (file)
@@ -147,14 +147,17 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     public static Config getConfigMapping(ConfigRegistryClient configRegistryClient,
-            Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
+            Map<String/* Namespace from yang file */,
+                    Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> mBeanEntries) {
         Map<String, Map<String, ModuleConfig>> factories = transform(configRegistryClient, mBeanEntries);
         return new Config(factories);
     }
 
     // TODO refactor
-    private static Map<String, Map<String, ModuleConfig>> transform(final ConfigRegistryClient configRegistryClient,
-            Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
+    private static Map<String/* Namespace from yang file */,
+            Map<String /* Name of module entry from yang file */, ModuleConfig>> transform
+    (final ConfigRegistryClient configRegistryClient, Map<String/* Namespace from yang file */,
+                    Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> mBeanEntries) {
         return Maps.transformEntries(mBeanEntries,
                 new Maps.EntryTransformer<String, Map<String, ModuleMXBeanEntry>, Map<String, ModuleConfig>>() {
 
@@ -164,9 +167,9 @@ public class EditConfig extends AbstractConfigNetconfOperation {
                                 new Maps.EntryTransformer<String, ModuleMXBeanEntry, ModuleConfig>() {
 
                                     @Override
-                                    public ModuleConfig transformEntry(String key, ModuleMXBeanEntry value) {
-                                        return new ModuleConfig(key, new InstanceConfig(configRegistryClient, value
-                                                .getAttributes()));
+                                    public ModuleConfig transformEntry(String key, ModuleMXBeanEntry moduleMXBeanEntry) {
+                                        return new ModuleConfig(key, new InstanceConfig(configRegistryClient, moduleMXBeanEntry
+                                                .getAttributes()), moduleMXBeanEntry.getProvidedServices().values());
                                     }
                                 });
                     }
@@ -184,7 +187,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
         EditConfigXmlParser.EditConfigExecution editConfigExecution;
         Config cfg = getConfigMapping(configRegistryClient, yangStoreSnapshot.getModuleMXBeanEntryMap());
         try {
-            editConfigExecution = editConfigXmlParser.fromXml(xml, cfg);
+            editConfigExecution = editConfigXmlParser.fromXml(xml, cfg, transactionProvider, configRegistryClient);
         } catch (IllegalStateException e) {
             logger.warn("Error parsing xml", e);
             final Map<String, String> errorInfo = new HashMap<>();
index d835dfd30f0abc0a95bbf51dc4cca7cfe5443a30..db82aa66fc9a2f3417db73a9c7bcc9940921117b 100644 (file)
@@ -12,17 +12,22 @@ 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.util.ConfigRegistryClient;
 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.operations.Datastore;
+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;
 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 {
 
@@ -38,7 +43,8 @@ public class EditConfigXmlParser {
     public EditConfigXmlParser() {
     }
 
-    EditConfigXmlParser.EditConfigExecution fromXml(final XmlElement xml, final Config cfgMapping)
+    EditConfigXmlParser.EditConfigExecution fromXml(final XmlElement xml, final Config cfgMapping,
+                                                    TransactionProvider transactionProvider, ConfigRegistryClient configRegistryClient)
             throws NetconfDocumentedException {
 
         EditStrategyType.resetDefaultStrategy();
@@ -81,12 +87,24 @@ public class EditConfigXmlParser {
         // Default op
         Optional<XmlElement> defaultContent = xml
                 .getOnlyChildElementWithSameNamespaceOptionally(EditConfigXmlParser.DEFAULT_OPERATION_KEY);
-        if (defaultContent.isPresent())
-            EditStrategyType.setDefaultStrategy(EditStrategyType.valueOf(defaultContent.get().getTextContent()));
+        if (defaultContent.isPresent()) {
+            String mergeStrategyString = defaultContent.get().getTextContent();
+            logger.trace("Setting merge strategy to {}", mergeStrategyString);
+            EditStrategyType editStrategyType = EditStrategyType.valueOf(mergeStrategyString);
+            // FIXME: thread safety, remove global state
+            EditStrategyType.setDefaultStrategy(editStrategyType);
+        }
+        // FIXME: thread safety, remove global state
+        Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
+        if (EditStrategyType.defaultStrategy() == 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);
+        return new EditConfigXmlParser.EditConfigExecution(xml, cfgMapping, configElement, testOption, instancesForFillingServiceRefMapping);
     }
 
     private void removeMountpointsFromConfig(XmlElement configElement, XmlElement mountpointsElement) {
@@ -123,9 +141,9 @@ public class EditConfigXmlParser {
         Map<String, Multimap<String, ModuleElementResolved>> resolvedXmlElements;
         TestOption testOption;
 
-        EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption) {
+        EditConfigExecution(XmlElement xml, Config configResolver, XmlElement configElement, TestOption testOption, Set<ObjectName> instancesForFillingServiceRefMapping) {
             this.editConfigXml = xml;
-            this.resolvedXmlElements = configResolver.fromXml(configElement);
+            this.resolvedXmlElements = configResolver.fromXml(configElement, instancesForFillingServiceRefMapping);
             this.testOption = testOption;
         }
 
index 123c03e9a18fb4daff3aa8201df8e31f8e135111..c8f83c88760f077323fff8235587bdbacad9cf7d 100644 (file)
@@ -31,7 +31,9 @@ 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;
@@ -86,10 +88,11 @@ public class EditConfigTest {
 
         Config cfg = mock(Config.class);
         XmlElement xmlElement = mock(XmlElement.class);
-        doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement);
+        Set<ObjectName> instancesForFillingServiceRefMapping = Collections.emptySet();
+        doReturn(resolvedXmlElements).when(cfg).fromXml(xmlElement, instancesForFillingServiceRefMapping);
 
         EditConfigExecution editConfigExecution = new EditConfigExecution(null, cfg, xmlElement,
-                EditConfigXmlParser.TestOption.testThenSet);
+                EditConfigXmlParser.TestOption.testThenSet, instancesForFillingServiceRefMapping);
 
         edit.getResponseInternal(XmlUtil.newDocument(), editConfigExecution);