Merge "Introducing simple merge strategy for config subsystem"
authorTony Tkacik <ttkacik@cisco.com>
Fri, 11 Jul 2014 11:35:41 +0000 (11:35 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 11 Jul 2014 11:35:41 +0000 (11:35 +0000)
30 files changed:
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionClient.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java
opendaylight/config/yang-test/.gitignore [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/.gitignore [new file with mode: 0644]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModule.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModuleFactory.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleFactory.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/MultipleDependenciesModuleStub.txt [new file with mode: 0644]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModule.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleFactory.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleStub.txt
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModule.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModuleFactory.java [deleted file]
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/util/NetconfTestImplModuleUtil.java [moved from opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleUtil.java with 69% similarity]
opendaylight/config/yang-test/src/main/yang/config-test-impl.yang
opendaylight/config/yang-test/src/test/java/org/opendaylight/controller/config/yang/test/impl/MultipleDependenciesModuleTest.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ServiceRegistryWrapper.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/MergeEditConfigStrategy.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategyTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/SSLUtil.java
opendaylight/netconf/netconf-it/src/test/resources/logback-test.xml [moved from opendaylight/netconf/netconf-it/src/test/resources/logback.xml with 83% similarity]
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_multiple-deps1.xml [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_multiple-deps2.xml [new file with mode: 0644]

index 335acc81fe67859386b3369269c15f3101d7e2f4..07bd63b7c7be8c78397b227ae40db7e53cb8da91 100644 (file)
@@ -53,12 +53,12 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
     private final ReadOnlyAtomicBoolean configBeanModificationDisabled;
 
     public DynamicWritableWrapper(Module module,
-            ModuleIdentifier moduleIdentifier,
-            TransactionIdentifier transactionIdentifier,
-            ReadOnlyAtomicBoolean configBeanModificationDisabled,
-            MBeanServer internalServer, MBeanServer configMBeanServer) {
+                                  ModuleIdentifier moduleIdentifier,
+                                  TransactionIdentifier transactionIdentifier,
+                                  ReadOnlyAtomicBoolean configBeanModificationDisabled,
+                                  MBeanServer internalServer, MBeanServer configMBeanServer) {
         super(module, true, moduleIdentifier, ObjectNameUtil
-                .createTransactionModuleON(transactionIdentifier.getName(), moduleIdentifier), getOperations(moduleIdentifier),
+                        .createTransactionModuleON(transactionIdentifier.getName(), moduleIdentifier), getOperations(moduleIdentifier),
                 internalServer, configMBeanServer);
         this.configBeanModificationDisabled = configBeanModificationDisabled;
     }
@@ -67,22 +67,19 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
             ModuleIdentifier moduleIdentifier) {
         Method validationMethod;
         try {
-            validationMethod = DynamicWritableWrapper.class.getMethod(
-                    "validate", new Class<?>[0]);
+            validationMethod = DynamicWritableWrapper.class.getMethod("validate");
         } catch (NoSuchMethodException e) {
-            throw new IllegalStateException("No such method exception on "
-                    + moduleIdentifier, e);
+            throw new IllegalStateException("No such method exception on " + moduleIdentifier, e);
         }
-        return new MBeanOperationInfo[] { new MBeanOperationInfo("Validation",
-                validationMethod) };
+        return new MBeanOperationInfo[]{new MBeanOperationInfo("Validation", validationMethod)};
     }
 
     @Override
     public synchronized void setAttribute(Attribute attribute)
-            throws AttributeNotFoundException, InvalidAttributeValueException,
-            MBeanException, ReflectionException {
-        if (configBeanModificationDisabled.get() == true)
+            throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+        if (configBeanModificationDisabled.get() == true) {
             throw new IllegalStateException("Operation is not allowed now");
+        }
 
         if (attribute.getName().equals("Attribute")) {
             setAttribute((Attribute) attribute.getValue());
@@ -92,7 +89,7 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
         try {
             if (attribute.getValue() instanceof ObjectName) {
                 attribute = fixDependencyAttribute(attribute);
-            } else if(attribute.getValue() instanceof ObjectName[]) {
+            } else if (attribute.getValue() instanceof ObjectName[]) {
                 attribute = fixDependencyListAttribute(attribute);
             }
 
@@ -104,24 +101,19 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
     }
 
     private Attribute fixDependencyListAttribute(Attribute attribute) {
-        AttributeHolder attributeHolder = attributeHolderMap
-                .get(attribute.getName());
+        AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName());
         if (attributeHolder.getRequireInterfaceOrNull() != null) {
-            attribute = new Attribute(attribute.getName(),
-                    fixObjectNames((ObjectName[]) attribute.getValue()));
+            attribute = new Attribute(attribute.getName(), fixObjectNames((ObjectName[]) attribute.getValue()));
         }
         return attribute;
     }
 
     private Attribute fixDependencyAttribute(Attribute attribute) {
-        AttributeHolder attributeHolder = attributeHolderMap
-                .get(attribute.getName());
+        AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName());
         if (attributeHolder.getRequireInterfaceOrNull() != null) {
-            attribute = new Attribute(attribute.getName(),
-                    fixObjectName((ObjectName) attribute.getValue()));
+            attribute = new Attribute(attribute.getName(), fixObjectName((ObjectName) attribute.getValue()));
         } else {
-            attribute = new Attribute(attribute.getName(),
-                    attribute.getValue());
+            attribute = new Attribute(attribute.getName(), attribute.getValue());
         }
         return attribute;
     }
@@ -145,8 +137,7 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
                 setAttribute(attribute);
                 result.add(attribute);
             } catch (Exception e) {
-                logger.warn("Setting attribute {} failed on {}",
-                        attribute.getName(), moduleIdentifier, e);
+                logger.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e);
                 throw new IllegalArgumentException(
                         "Setting attribute failed - " + attribute.getName()
                                 + " on " + moduleIdentifier, e);
index 4f02db5a3807095c0302ee1446eb765a2858ea77..f5381424de8c217414a326212c69b25879c52fe8 100644 (file)
@@ -41,4 +41,14 @@ public interface ConfigTransactionClient extends
     void destroyModule(String moduleName, String instanceName) throws InstanceNotFoundException;
 
     void setAttribute(ObjectName on, String jmxName, Attribute attribute);
+
+    /*
+     * Get the attribute named jmxName from the Object with ObjectName on
+     *
+     * @param on - ObjectName of the Object from which the attribute should be read
+     * @param jmxName - name of the attribute to be read
+     *
+     * @return Attribute of Object on with attribute name jmxName
+     */
+    Attribute getAttribute(ObjectName on, String jmxName);
 }
index 4cf766a8120ef4c559eb45a9883c7583c1983f8b..bc188515538485f9a13f87366a281a893a5984ae 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.config.util;
 
 import java.util.Map;
 import java.util.Set;
+
 import javax.management.Attribute;
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
@@ -17,6 +18,7 @@ import javax.management.JMX;
 import javax.management.MBeanException;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
+
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
@@ -270,6 +272,20 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
         }
     }
 
+    @Override
+    public Attribute getAttribute(ObjectName on, String attrName) {
+        if (ObjectNameUtil.getTransactionName(on) == null)
+            throw new IllegalArgumentException("Not in transaction instance "
+                    + on + ", no transaction name present");
+
+        try {
+            return new Attribute(attrName, configMBeanServer.getAttribute(on,attrName));
+        } catch (JMException e) {
+            throw new IllegalStateException("Unable to get attribute "
+                    + attrName + " for " + on, e);
+        }
+    }
+
     @Override
     public Set<String> getAvailableModuleFactoryQNames() {
         return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames();
diff --git a/opendaylight/config/yang-test/.gitignore b/opendaylight/config/yang-test/.gitignore
deleted file mode 100644 (file)
index 1439354..0000000
+++ /dev/null
@@ -1 +0,0 @@
-src/main/java/org/opendaylight/controller/config/yang/test/impl/*
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/.gitignore b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/.gitignore
new file mode 100644 (file)
index 0000000..27d1535
--- /dev/null
@@ -0,0 +1 @@
+*.java
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModule.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModule.java
deleted file mode 100644 (file)
index 6046665..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.opendaylight.controller.config.yang.test.impl;
-public class DepTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModule {
-    public DepTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-        super(identifier, dependencyResolver);
-    }
-
-    public DepTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.DepTestImplModule oldModule, java.lang.AutoCloseable oldInstance) {
-        super(identifier, dependencyResolver, oldModule, oldInstance);
-    }
-
-    @Override
-    public void customValidation() {
-        // add custom validation form module attributes here.
-    }
-
-    @Override
-    public java.lang.AutoCloseable createInstance() {
-        return new AutoCloseable() {
-            @Override
-            public void close() throws Exception {
-            }
-        };
-
-    }
-
-}
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModuleFactory.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModuleFactory.java
deleted file mode 100644 (file)
index 026dd9a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class DepTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModuleFactory {
-
-}
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java
deleted file mode 100644 (file)
index bda3548..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.opendaylight.controller.config.yang.test.impl;
-public class IdentityTestModule extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModule {
-    public IdentityTestModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-        super(identifier, dependencyResolver);
-    }
-
-    public IdentityTestModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.IdentityTestModule oldModule, java.lang.AutoCloseable oldInstance) {
-        super(identifier, dependencyResolver, oldModule, oldInstance);
-    }
-
-    @Override
-    public void customValidation() {
-        // add custom validation form module attributes here.
-    }
-
-    @Override
-    public java.lang.AutoCloseable createInstance() {
-        org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
-        logger.info("Afi: {}", getAfi());
-        logger.info("Afi class: {}", getAfiIdentity());
-
-        for (Identities identities : getIdentities()) {
-            logger.info("Identities Afi class: {}", identities.resolveAfi());
-            logger.info("Identities Safi class: {}", identities.resolveSafi());
-
-        }
-        logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
-
-        return new AutoCloseable() {
-            @Override
-            public void close() throws Exception {
-            }
-        };
-
-    }
-
-}
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleFactory.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleFactory.java
deleted file mode 100644 (file)
index 3a4348d..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class IdentityTestModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModuleFactory {
-
-}
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/MultipleDependenciesModuleStub.txt b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/MultipleDependenciesModuleStub.txt
new file mode 100644 (file)
index 0000000..80c1e54
--- /dev/null
@@ -0,0 +1,5 @@
+        return new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+            }
+        };
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModule.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModule.java
deleted file mode 100644 (file)
index ab43dea..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.opendaylight.controller.config.yang.test.impl;
-public class NetconfTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModule {
-    public NetconfTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-        super(identifier, dependencyResolver);
-    }
-
-    public NetconfTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModule oldModule, java.lang.AutoCloseable oldInstance) {
-        super(identifier, dependencyResolver, oldModule, oldInstance);
-    }
-
-    @Override
-    public void customValidation() {
-        // add custom validation form module attributes here.
-    }
-
-    @Override
-    public java.lang.AutoCloseable createInstance() {
-return NetconfTestImplModuleUtil.registerRuntimeBeans(this);
-
-    }
-
-}
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleFactory.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleFactory.java
deleted file mode 100644 (file)
index 587089b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class NetconfTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModuleFactory {
-
-}
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModule.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModule.java
deleted file mode 100644 (file)
index 2880b46..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.opendaylight.controller.config.yang.test.impl;
-public class TestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModule {
-    public TestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-        super(identifier, dependencyResolver);
-    }
-
-    public TestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.test.impl.TestImplModule oldModule, java.lang.AutoCloseable oldInstance) {
-        super(identifier, dependencyResolver, oldModule, oldInstance);
-    }
-
-    @Override
-    public void customValidation() {
-        // add custom validation form module attributes here.
-    }
-
-    @Override
-    public java.lang.AutoCloseable createInstance() {
-        return new AutoCloseable() {
-            @Override
-            public void close() throws Exception {
-            }
-        };
-
-    }
-
-}
diff --git a/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModuleFactory.java b/opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModuleFactory.java
deleted file mode 100644 (file)
index de9ac2f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-package org.opendaylight.controller.config.yang.test.impl;
-public class TestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModuleFactory {
-
-}
@@ -1,13 +1,34 @@
 
 
-package org.opendaylight.controller.config.yang.test.impl;
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 
-import com.google.common.collect.Lists;
+package org.opendaylight.controller.config.yang.test.util;
 
+import com.google.common.collect.Lists;
 import java.util.List;
+import org.opendaylight.controller.config.yang.test.impl.Asdf;
+import org.opendaylight.controller.config.yang.test.impl.Deep2;
+import org.opendaylight.controller.config.yang.test.impl.Deep3;
+import org.opendaylight.controller.config.yang.test.impl.Deep4;
+import org.opendaylight.controller.config.yang.test.impl.InnerInnerRunningDataRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataAdditionalRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataRuntimeRegistration;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModule;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeMXBean;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeRegistration;
+import org.opendaylight.controller.config.yang.test.impl.NotStateBean;
+import org.opendaylight.controller.config.yang.test.impl.RetValContainer;
+import org.opendaylight.controller.config.yang.test.impl.RetValList;
 
 public class NetconfTestImplModuleUtil {
-    static NetconfTestImplRuntimeRegistration registerRuntimeBeans(final NetconfTestImplModule module) {
+    public static NetconfTestImplRuntimeRegistration registerRuntimeBeans(final NetconfTestImplModule module) {
         NetconfTestImplRuntimeRegistration reg = module.getRootRuntimeBeanRegistratorWrapper().register(new NetconfTestImplRuntimeMXBean() {
 
             @Override
index 4b006bc72e52c3026130db4b556e62fd340523da..e7aa64d7a621cc5ecdfa4781c6389e576b7865c1 100644 (file)
@@ -41,6 +41,12 @@ module config-test-impl {
         config:java-name-prefix IdentityTest;
     }
 
+    identity multiple-dependencies {
+        base config:module-type;
+        config:provided-service test:testing;
+        config:java-name-prefix MultipleDependencies;
+    }
+
     augment "/config:modules/config:module/config:configuration" {
             case impl-identity-test {
                 when "/config:modules/config:module/config:type = 'impl-identity-test'";
@@ -444,6 +450,24 @@ module config-test-impl {
         }
     }
 
+
+    augment "/config:modules/config:module/config:configuration" {
+        case multiple-dependencies {
+            when "/config:modules/config:module/config:type = 'multiple-dependencies'";
+            container multiple-dependencies {
+                list testing-deps {
+                    uses config:service-ref {
+                        refine type {
+                            mandatory true;
+                            config:required-identity test:testing;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
     identity test-rpc;
     identity inner-test-rpc;
     identity inner-inner-test-rpc;
diff --git a/opendaylight/config/yang-test/src/test/java/org/opendaylight/controller/config/yang/test/impl/MultipleDependenciesModuleTest.java b/opendaylight/config/yang-test/src/test/java/org/opendaylight/controller/config/yang/test/impl/MultipleDependenciesModuleTest.java
new file mode 100644 (file)
index 0000000..2df15d0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yang.test.impl;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getInstanceName;
+import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getTransactionName;
+
+import java.util.List;
+import javax.management.ObjectName;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+
+public class MultipleDependenciesModuleTest extends AbstractConfigTest {
+    private static final MultipleDependenciesModuleFactory factory = new MultipleDependenciesModuleFactory();
+
+    @Before
+    public void setUp() throws Exception {
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory));
+    }
+
+    @Test
+    public void testMultipleDependencies() throws Exception {
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+        ObjectName d1 = transaction.createModule(factory.getImplementationName(), "d1");
+        ObjectName d2 = transaction.createModule(factory.getImplementationName(), "d2");
+
+        assertEquals(transaction.getTransactionName(), getTransactionName(d1));
+
+        ObjectName parent = transaction.createModule(factory.getImplementationName(), "parent");
+        MultipleDependenciesModuleMXBean multipleDependenciesModuleMXBean = transaction.newMXBeanProxy(parent, MultipleDependenciesModuleMXBean.class);
+        multipleDependenciesModuleMXBean.setTestingDeps(asList(d1, d2));
+        List<ObjectName> found = multipleDependenciesModuleMXBean.getTestingDeps();
+        ObjectName d1WithoutTxName = found.get(0);
+        assertEquals(getInstanceName(d1), getInstanceName(d1WithoutTxName));
+        // check that transaction name gets stripped automatically from attribute.
+        // d1,2 contained tx name, found doesn't
+        assertNull(getTransactionName(d1WithoutTxName));
+        transaction.commit();
+    }
+}
index f86d641112585515198e9cbad18cce3c62a89389..2b363ea153960eeb98754855ffa54473e43fad14 100644 (file)
@@ -13,11 +13,12 @@ import java.util.Map;
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.yangtools.yang.common.QName;
 
 public class ServiceRegistryWrapper {
 
-    private ServiceReferenceReadableRegistry configServiceRefRegistry;
+    private final ServiceReferenceReadableRegistry configServiceRefRegistry;
 
     public ServiceRegistryWrapper(ServiceReferenceReadableRegistry configServiceRefRegistry) {
         this.configServiceRefRegistry = configServiceRefRegistry;
@@ -43,7 +44,12 @@ public class ServiceRegistryWrapper {
 
         String qNameOfService = configServiceRefRegistry.getServiceInterfaceName(namespace, serviceName);
         try {
-            return configServiceRefRegistry.getServiceReference(qNameOfService, refName);
+            /*
+             Remove transaction name as this is redundant - will be stripped in DynamicWritableWrapper,
+             and makes it hard to compare with service references got from MXBean attributes
+            */
+            return ObjectNameUtil.withoutTransactionName(
+                    configServiceRefRegistry.getServiceReference(qNameOfService, refName));
         } catch (InstanceNotFoundException e) {
             throw new IllegalArgumentException("No serviceInstance mapped to " + refName
                     + " under service name " + serviceName + " , " + refNameToInstance.keySet(), e);
index 37ad2bb22260ab45027b635d5671da8077d823b7..59a1d4fe7141bbe54a2dc770a4d2c789819bf52d 100644 (file)
@@ -104,8 +104,11 @@ public final class Services {
 
             String serviceName =  ObjectNameAttributeReadingStrategy.checkPrefixAndExtractServiceName(typeElement, prefixNamespace);
 
-            Map<String, String> innerMap = Maps.newHashMap();
-            namespaceToServices.put(serviceName, innerMap);
+            Map<String, String> innerMap = namespaceToServices.get(serviceName);
+            if (innerMap == null) {
+                innerMap = Maps.newHashMap();
+                namespaceToServices.put(serviceName, innerMap);
+            }
 
             List<XmlElement> instances = service.getChildElements(XmlNetconfConstants.INSTANCE_KEY);
             service.checkUnrecognisedElements(instances, typeElement);
index 6ebeeaa07ba86034991ffd584448135bd2ec5b13..d8ceb311038e6f0602832448a32de27db6d3e664 100644 (file)
@@ -8,6 +8,10 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
 
+import static java.util.Arrays.asList;
+
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import javax.management.Attribute;
@@ -30,7 +34,7 @@ public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
 
     @Override
     void handleMissingInstance(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta,
-            String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
+                               String module, String instance, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
         throw new NetconfConfigHandlingException(
                 String.format("Unable to handle missing instance, no missing instances should appear at this point, missing: %s : %s ",
                         module,
@@ -39,6 +43,7 @@ public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
                 NetconfDocumentedException.ErrorTag.operation_failed,
                 NetconfDocumentedException.ErrorSeverity.error);
     }
+
     @Override
     void executeStrategy(Map<String, AttributeConfigElement> configuration, ConfigTransactionClient ta, ObjectName on, ServiceRegistryWrapper services) throws NetconfConfigHandlingException {
 
@@ -51,10 +56,16 @@ public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
                     continue;
                 }
 
-                Object value = ace.getResolvedValue().get();
-                ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), value));
-                logger.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), value, on);
+                Object toBeMergedIn = ace.getResolvedValue().get();
+                // Get the existing values so we can merge the new values with them.
+                Attribute currentAttribute = ta.getAttribute(on, ace.getJmxName());
+                Object oldValue = (currentAttribute != null ? currentAttribute.getValue() : null);
+                // Merge value with currentValue
+                toBeMergedIn = merge(oldValue, toBeMergedIn);
+                ta.setAttribute(on, ace.getJmxName(), new Attribute(ace.getJmxName(), toBeMergedIn));
+                logger.debug("Attribute {} set to {} for {}", configAttributeEntry.getKey(), toBeMergedIn, on);
             } catch (Exception e) {
+                logger.error("Error while merging objectnames of {}", on, e);
                 throw new NetconfConfigHandlingException(String.format("Unable to set attributes for %s, Error with attribute %s : %s ",
                         on,
                         configAttributeEntry.getKey(),
@@ -65,4 +76,44 @@ public class MergeEditConfigStrategy extends AbstractEditConfigStrategy {
             }
         }
     }
+
+    /**
+     * Merge value into current value
+     * Currently, this is only implemented for arrays of ObjectNames, but that is the
+     * most common case for which it is needed.
+     */
+    protected Object merge(Object oldValue, Object toBeMergedIn) {
+        if (oldValue instanceof ObjectName[] && toBeMergedIn instanceof ObjectName[]) {
+            toBeMergedIn = mergeObjectNameArrays((ObjectName[]) oldValue, (ObjectName[]) toBeMergedIn);
+        }
+        return toBeMergedIn;
+    }
+
+    /**
+     * Merge value into current values
+     * This implements for arrays of ObjectNames, but that is the
+     * most common case for which it is needed.
+     *
+     * @param oldValue - the new values to be merged into existing values
+     * @param toBeMergedIn - the existing values
+     *
+     * @return an ObjectName[] consisting the elements of currentValue with an elements from values not already present in currentValue added
+     *
+     */
+    protected ObjectName[] mergeObjectNameArrays(ObjectName[] oldValue, ObjectName[] toBeMergedIn) {
+        List<ObjectName> newValueList = new ArrayList<>();
+        newValueList.addAll(asList(oldValue));
+        /*
+         It is guaranteed that old values do not contain transaction name.
+         Since toBeMergedIn is filled using service references translated by ServiceRegistryWrapper, it
+         is also guaranteed that this list will not contain transaction names.
+         Run through the list of values to be merged.  If we don't have them already, add them to the list.
+         */
+        for (ObjectName objName : toBeMergedIn) {
+            if (!newValueList.contains(objName)) {
+                newValueList.add(objName);
+            }
+        }
+        return newValueList.toArray(new ObjectName[newValueList.size()]);
+    }
 }
diff --git a/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategyTest.java b/opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/MergeEditConfigStrategyTest.java
new file mode 100644 (file)
index 0000000..b187749
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.createReadOnlyModuleON;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+import javax.management.ObjectName;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModule;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
+
+public class MergeEditConfigStrategyTest extends AbstractConfigTest {
+    private static final MultipleDependenciesModuleFactory factory = new MultipleDependenciesModuleFactory();
+    public static final String PARENT = "parent";
+    public static final String D1 = "d1";
+    public static final String D2 = "d2";
+    public static final String D3 = "d3";
+
+    private static final String factoryName = factory.getImplementationName();
+
+    @Before
+    public void setUp() throws Exception {
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory));
+
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+        ObjectName d1 = transaction.createModule(factoryName, D1);
+        ObjectName d2 = transaction.createModule(factoryName, D2);
+        ObjectName parent = transaction.createModule(factoryName, PARENT);
+        MultipleDependenciesModuleMXBean multipleDependenciesModuleMXBean = transaction.newMXBeanProxy(parent,
+                MultipleDependenciesModuleMXBean.class);
+        multipleDependenciesModuleMXBean.setTestingDeps(asList(d1, d2));
+        transaction.createModule(factoryName, D3);
+        transaction.commit();
+    }
+
+    @Test
+    public void testMergingOfObjectNames() throws Exception {
+        MergeEditConfigStrategy strategy = new MergeEditConfigStrategy();
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+
+        // add D3
+
+        AttributeConfigElement attributeConfigElement = mock(AttributeConfigElement.class);
+        doReturn(Optional.of(new ObjectName[] {createReadOnlyModuleON(factoryName, D3)})).when(attributeConfigElement).getResolvedValue();
+        doReturn("mocked").when(attributeConfigElement).toString();
+        String attributeName = MultipleDependenciesModule.testingDepsJmxAttribute.getAttributeName();
+        doReturn(attributeName).when(attributeConfigElement).getJmxName();
+        Map<String, AttributeConfigElement> configuration = ImmutableMap.of(
+                attributeName,
+                attributeConfigElement);
+
+        strategy.executeConfiguration(factoryName, PARENT, configuration, transaction,
+                mock(ServiceRegistryWrapper.class));
+        transaction.commit();
+
+        // parent's attribute should contain d1,d2,d3
+        MultipleDependenciesModuleMXBean proxy = configRegistryClient.newMXBeanProxy(
+                createReadOnlyModuleON(factoryName, PARENT),
+                MultipleDependenciesModuleMXBean.class);
+        List<ObjectName> testingDeps = proxy.getTestingDeps();
+        List<ObjectName> expected = asList(createReadOnlyModuleON(factoryName, D1),
+                createReadOnlyModuleON(factoryName, D2),
+                createReadOnlyModuleON(factoryName, D3));
+        assertEquals(expected, testingDeps);
+    }
+}
index f7091beba5fcb09f26cb1248dbdfdd52d600db77..eb99be0dc08f006ece7f7a93193f103bfa2bfb61 100644 (file)
@@ -18,17 +18,18 @@ import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertCo
 import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertElementsCount;
 import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToDocument;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.InetSocketAddress;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
-
 import javax.management.InstanceNotFoundException;
 import javax.management.Notification;
 import javax.management.NotificationListener;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -37,7 +38,6 @@ import org.mockito.stubbing.Answer;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
@@ -63,10 +63,6 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
-
 public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
 
     private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
@@ -76,8 +72,7 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
 
     @Before
     public void setUp() throws Exception {
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,NetconfITTest.getModuleFactoriesS().toArray(
-                new ModuleFactory[0])));
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,NetconfITTest.FACTORIES));
 
         NetconfMonitoringServiceImpl monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
 
index 0969bd92a59a7cb6132a2b3b6cb5ad713af5077e..2f7bd20d615b074a945bf49e2c60c9559c3df7e7 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.netconf.it;
 
+import static java.util.Arrays.asList;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doAnswer;
@@ -99,7 +100,7 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
     }
 
     protected List<ModuleFactory> getModuleFactories() {
-        return NetconfITTest.getModuleFactoriesS();
+        return asList(NetconfITTest.FACTORIES);
     }
 
     @Test
index 60a5207daa2e74b54cbc5a1a2b1ec9dd423a3f2b..8e69e6a345ffef868c2ed4e5bc454c440dc989a4 100644 (file)
@@ -16,6 +16,7 @@ import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
+import com.google.common.base.Function;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -28,6 +29,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -39,11 +41,14 @@ import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
@@ -81,23 +86,27 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
 
     private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
-    private DefaultCommitNotificationProducer commitNot;
+    private DefaultCommitNotificationProducer commitNotificationProducer;
     private NetconfServerDispatcher dispatch;
 
     private NetconfClientDispatcherImpl clientDispatcher;
 
+    static ModuleFactory[] FACTORIES = {new TestImplModuleFactory(), new DepTestImplModuleFactory(),
+            new NetconfTestImplModuleFactory(), new IdentityTestModuleFactory(),
+            new MultipleDependenciesModuleFactory()};
+
     @Before
     public void setUp() throws Exception {
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,getModuleFactories().toArray(
-                new ModuleFactory[0])));
+        initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
+                FACTORIES
+        ));
 
         loadMessages();
 
         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
         factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
 
-
-        commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+        commitNotificationProducer = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
         dispatch = createDispatcher(factoriesListener);
         ChannelFuture s = dispatch.createServer(tcpAddress);
@@ -107,7 +116,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     }
 
     private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
-        return super.createDispatcher(factoriesListener, getNetconfMonitoringListenerService(), commitNot);
+        return super.createDispatcher(factoriesListener, getNetconfMonitoringListenerService(), commitNotificationProducer);
     }
 
     static NetconfMonitoringServiceImpl getNetconfMonitoringListenerService() {
@@ -120,7 +129,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @After
     public void tearDown() throws Exception {
-        commitNot.close();
+        commitNotificationProducer.close();
         clientDispatcher.close();
     }
 
@@ -155,14 +164,6 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         return yangDependencies;
     }
 
-    protected List<ModuleFactory> getModuleFactories() {
-        return getModuleFactoriesS();
-    }
-
-    static List<ModuleFactory> getModuleFactoriesS() {
-        return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
-                new NetconfTestImplModuleFactory(), new IdentityTestModuleFactory());
-    }
 
     @Test
     public void testNetconfClientDemonstration() throws Exception {
@@ -392,4 +393,66 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         doReturn(codec).when(ret).getIdentityCodec();
         return ret;
     }
+
+
+    @Test
+    public void testMultipleDependencies() throws Exception {
+        // push first xml, should add parent and d1,d2 dependencies
+        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+            Document rpcReply = netconfClient.sendMessage(
+                    XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps1.xml"))
+                    .getDocument();
+            assertIsOK(rpcReply);
+            commit(netconfClient);
+        }
+        // verify that parent.getTestingDeps == d1,d2
+        MultipleDependenciesModuleMXBean parentProxy = configRegistryClient.newMXBeanProxy(
+                configRegistryClient.lookupConfigBean(MultipleDependenciesModuleFactory.NAME, "parent"),
+                MultipleDependenciesModuleMXBean.class);
+        {
+            List<ObjectName> testingDeps = parentProxy.getTestingDeps();
+            assertEquals(2, testingDeps.size());
+            Set<String> actualRefs = getServiceReferences(testingDeps);
+            assertEquals(Sets.newHashSet("ref_d1", "ref_d2"), actualRefs);
+        }
+
+        // push second xml, should add d3 to parent's dependencies
+        mergeD3(parentProxy);
+        // push second xml again, to test that d3 is not added again
+        mergeD3(parentProxy);
+    }
+
+    public void mergeD3(MultipleDependenciesModuleMXBean parentProxy) throws Exception {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient(
+                "test " + tcpAddress.toString(), clientDispatcher, getClientConfiguration(tcpAddress, 5000))) {
+
+            Document rpcReply = netconfClient.sendMessage(
+                    XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps2.xml"))
+                    .getDocument();
+            assertIsOK(rpcReply);
+            commit(netconfClient);
+        }
+        {
+            List<ObjectName> testingDeps = parentProxy.getTestingDeps();
+            assertEquals(3, testingDeps.size());
+            Set<String> actualRefs = getServiceReferences(testingDeps);
+            assertEquals(Sets.newHashSet("ref_d1", "ref_d2", "ref_d3"), actualRefs);
+        }
+    }
+
+    public Set<String> getServiceReferences(List<ObjectName> testingDeps) {
+        return new HashSet<>(Lists.transform(testingDeps, new Function<ObjectName, String>() {
+            @Override
+            public String apply(ObjectName input) {
+                return ObjectNameUtil.getReferenceName(input);
+            }
+        }));
+    }
+
+    public void commit(TestingNetconfClient netconfClient) throws Exception {
+        Document rpcReply;
+        rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml"))
+                .getDocument();
+        assertIsOK(rpcReply);
+    }
 }
index 3b263f7e75cc826b55b893a76a1f5fbf4b051c34..05e32577fe771f1e8a47a30bdd3ecbceb43a189d 100644 (file)
@@ -13,6 +13,10 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
 
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -22,14 +26,11 @@ import java.net.Socket;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
-
 import junit.framework.Assert;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
@@ -53,11 +54,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
-
 public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
 
     private static final Logger logger =  LoggerFactory.getLogger(NetconfITTest.class);
@@ -74,8 +70,7 @@ public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
 
     @Before
     public void setUp() throws Exception {
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, NetconfITTest.getModuleFactoriesS().toArray(
-                new ModuleFactory[0])));
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, NetconfITTest.FACTORIES));
 
         monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
 
index 07ca2f134dda4f5910bc4acf11dfd0ba650e4199..4d232a619a49affd154c46d9fd6aa92ec08592b6 100644 (file)
@@ -28,7 +28,7 @@ public final class SSLUtil {
     }
 
     public static SSLContext initializeSecureContext(final String pass, final InputStream ksKeysFile, final InputStream ksTrustFile,
-            final String algorithm) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
+                                                     final String algorithm) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
             UnrecoverableKeyException, KeyManagementException {
 
         Preconditions.checkNotNull(ksTrustFile, "ksTrustFile cannot be null");
similarity index 83%
rename from opendaylight/netconf/netconf-it/src/test/resources/logback.xml
rename to opendaylight/netconf/netconf-it/src/test/resources/logback-test.xml
index fa467a1080f1c605008f5da36cfab7e1d277a7f1..c5037d34ed4ac01fcea4b5dd264b8f715ad2cc9c 100644 (file)
@@ -6,7 +6,7 @@
         </encoder>
     </appender>
 
-  <logger name="org.opendaylight.controller.netconf" level="DEBUG"/>
+  <logger name="org.opendaylight.controller.netconf" level="TRACE"/>
 
   <root level="error">
     <appender-ref ref="STDOUT" />
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_multiple-deps1.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_multiple-deps1.xml
new file mode 100644 (file)
index 0000000..0a02114
--- /dev/null
@@ -0,0 +1,59 @@
+<?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">
+    <target>
+      <candidate/>
+    </target>
+    <default-operation>merge</default-operation>
+    <test-option>set</test-option>
+    <config>
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <name>d1</name>
+          <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+        </module>
+        <module>
+          <name>d2</name>
+          <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+        </module>
+        <module>
+          <name>parent</name>
+          <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+
+          <multiple-dependencies xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+            <testing-deps>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+              <name>ref_d1</name>
+            </testing-deps>
+            <testing-deps>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+              <name>ref_d2</name>
+            </testing-deps>
+          </multiple-dependencies>
+
+        </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_d1</name>
+            <provider>/modules/module[type='multiple-dependencies'][name='d1']
+            </provider>
+          </instance>
+        </service>
+        <service>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+          <instance>
+            <name>ref_d2</name>
+            <provider>/modules/module[type='multiple-dependencies'][name='d2']
+            </provider>
+          </instance>
+        </service>
+      </services>
+    </config>
+  </edit-config>
+</rpc>
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_multiple-deps2.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_merge_multiple-deps2.xml
new file mode 100644 (file)
index 0000000..d331976
--- /dev/null
@@ -0,0 +1,39 @@
+<?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">
+    <target>
+      <candidate/>
+    </target>
+    <default-operation>merge</default-operation>
+    <test-option>set</test-option>
+    <config>
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <name>d3</name>
+          <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+        </module>
+        <module>
+          <name>parent</name>
+          <type xmlns:th-java="urn:opendaylight:params:xml:ns:yang:controller:test:impl">th-java:multiple-dependencies</type>
+          <multiple-dependencies xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+            <testing-deps>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+              <name>ref_d3</name>
+            </testing-deps>
+          </multiple-dependencies>
+        </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_d3</name>
+            <provider>/modules/module[type='multiple-dependencies'][name='d3']
+            </provider>
+          </instance>
+        </service>
+      </services>
+    </config>
+  </edit-config>
+</rpc>