Merge "BUG 1330 - list key counts|values diff in payload and URI"
authorTom Pantelis <tpanteli@brocade.com>
Fri, 11 Jul 2014 14:55:36 +0000 (14:55 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 11 Jul 2014 14:55:36 +0000 (14:55 +0000)
54 files changed:
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java
opendaylight/commons/opendaylight/pom.xml
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/distribution/opendaylight/src/main/resources/configuration/cors-config.xml
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataChangeListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractSchemaAwareTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AssertCollections.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeListener.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationOperation.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java
opendaylight/md-sal/sal-test-model/pom.xml
opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java [new file with mode: 0644]
opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-mdsal-augment-test.yang [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]
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/IEEE8021Q.java

index fe456f3f8ebe6f6237352cb09f5b6a7dc8056398..4efcada2f8ed9ef7fd0d2774c5b41cfb6e265ba1 100644 (file)
@@ -695,6 +695,8 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
             dot1q.setVid(vlan);
             dot1q.setEtherType(EtherTypes.ARP.shortValue());
             dot1q.setPayload(arp);
+            dot1q.setCfi((byte)0);
+            dot1q.setPcp((byte)0);
             ethernet.setEtherType(EtherTypes.VLANTAGGED.shortValue());
             ethernet.setPayload(dot1q);
         }
index bf84183b75b755b9099374d3d2365432a9621288..28c23c8259cd9ca76492fb154b52e0767b67d98f 100644 (file)
         <artifactId>sal-restconf-broker</artifactId>
         <version>${mdsal.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-test-model</artifactId>
+        <version>${mdsal.version}</version>
+      </dependency>
 
       <!-- SAL Extension bundles -->
       <dependency>
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 00abf6cf339a036de0fe3285fdfb73a817232808..c148b83a7a136d47905bcbb0019169e3f2c097f3 100644 (file)
@@ -7,48 +7,61 @@
   -->
 
 <Host>
-    <!-- Filters are allowed here, only serving as a template -->
-    <filter-template>
-        <filter-name>CorsFilter</filter-name>
-        <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
-        <init-param>
-            <param-name>cors.allowed.origins</param-name>
-            <param-value>*</param-value>
-        </init-param>
-        <init-param>
-            <param-name>cors.allowed.methods</param-name>
-            <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
-        </init-param>
-        <init-param>
-            <param-name>cors.allowed.headers</param-name>
-            <param-value>Content-Type,X-Requested-With,accept,authorization,
-                origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers
-            </param-value>
-        </init-param>
-        <init-param>
-            <param-name>cors.exposed.headers</param-name>
-            <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
-        </init-param>
-        <init-param>
-            <param-name>cors.support.credentials</param-name>
-            <param-value>true</param-value>
-        </init-param>
-        <init-param>
-            <param-name>cors.preflight.maxage</param-name>
-            <param-value>10</param-value>
-        </init-param>
-    </filter-template>
+  <!-- Filters are allowed here, only serving as a template -->
+  <filter-template>
+    <filter-name>CorsFilter</filter-name>
+    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
+    <init-param>
+      <param-name>cors.allowed.origins</param-name>
+      <param-value>*</param-value>
+    </init-param>
+    <init-param>
+      <param-name>cors.allowed.methods</param-name>
+      <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
+    </init-param>
+    <init-param>
+      <param-name>cors.allowed.headers</param-name>
+      <param-value>Content-Type,X-Requested-With,accept,authorization,
+        origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers
+      </param-value>
+    </init-param>
+    <init-param>
+      <param-name>cors.exposed.headers</param-name>
+      <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
+    </init-param>
+    <init-param>
+      <param-name>cors.support.credentials</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>cors.preflight.maxage</param-name>
+      <param-value>10</param-value>
+    </init-param>
+  </filter-template>
+
+  <Context path="/restconf">
+    <filter>
+      <filter-name>CorsFilter</filter-name>
+      <!-- init params can be added/overriden if template is used -->
+    </filter>
+    <!-- references to templates without <filter> declaration are not allowed -->
+    <filter-mapping>
+      <filter-name>CorsFilter</filter-name>
+      <url-pattern>/*</url-pattern>
+    </filter-mapping>
+  </Context>
+
+  <Context path="/apidoc">
+    <filter>
+      <filter-name>CorsFilter</filter-name>
+      <!-- init params can be added/overriden if template is used -->
+    </filter>
+    <!-- references to templates without <filter> declaration are not allowed -->
+    <filter-mapping>
+      <filter-name>CorsFilter</filter-name>
+      <url-pattern>/*</url-pattern>
+    </filter-mapping>
+  </Context>
 
-    <Context path="/restconf">
-        <filter>
-            <filter-name>CorsFilter</filter-name>
-            <!-- init params can be added/overriden if template is used -->
-        </filter>
-        <!-- references to templates without <filter> declaration are not allowed -->
-        <filter-mapping>
-            <filter-name>CorsFilter</filter-name>
-            <url-pattern>/*</url-pattern>
-        </filter-mapping>
-    </Context>
 
 </Host>
index 8e286391deb31fb1d81ad56be4b69e8c509df229..74cceb1cbd55fc786b78e3f111b2a82a60bd8751 100644 (file)
       <groupId>org.opendaylight.yangtools.model</groupId>
       <artifactId>ietf-inet-types</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.reflections</groupId>
-      <artifactId>reflections</artifactId>
-      <scope>compile</scope>
-    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
       <artifactId>ietf-topology-l3-unicast-igp</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-test-model</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
index 8723fdf82a931b846482914fd5e85e69e8c10cf1..d275c838f25adacc554898b36db32aa47b7cfaa6 100644 (file)
@@ -8,12 +8,11 @@
 package org.opendaylight.controller.md.sal.binding.impl;
 
 import java.lang.reflect.Method;
-import java.lang.reflect.Type;
 import java.util.AbstractMap.SimpleEntry;
+import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map.Entry;
+import java.util.Set;
 
 import javax.annotation.Nullable;
 
@@ -21,13 +20,13 @@ import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizat
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
-import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
@@ -40,6 +39,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 import org.slf4j.Logger;
@@ -48,7 +50,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
@@ -99,8 +101,8 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
                 if (child instanceof AugmentationNode) {
                     ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument> builder()
                             .addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build();
-                    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(
-                            childArgs);
+                    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+                            .create(childArgs);
                     return toDOMEntry(childPath, child);
                 }
             }
@@ -121,7 +123,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
      */
     public Optional<InstanceIdentifier<? extends DataObject>> toBinding(
             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
-                    throws DeserializationException {
+            throws DeserializationException {
 
         PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments());
         // Used instance-identifier codec do not support serialization of last
@@ -138,7 +140,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     private Optional<InstanceIdentifier<? extends DataObject>> toBindingAugmented(
             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
-                    throws DeserializationException {
+            throws DeserializationException {
         Optional<InstanceIdentifier<? extends DataObject>> potential = toBindingImpl(normalized);
         // Shorthand check, if codec already supports deserialization
         // of AugmentationIdentifier we will return
@@ -188,7 +190,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     private Optional<InstanceIdentifier<? extends DataObject>> toBindingImpl(
             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
-                    throws DeserializationException {
+            throws DeserializationException {
         org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath;
 
         try {
@@ -207,10 +209,10 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
     private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
             throws DataNormalizationException {
         DataNormalizationOperation<?> op = findNormalizationOperation(normalized);
-        ifop.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
+        if (op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
             return true;
         }
-        if(op.isLeaf()) {
+        if (op.isLeaf()) {
             return true;
         }
         return false;
@@ -218,7 +220,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     private DataNormalizationOperation<?> findNormalizationOperation(
             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
-                    throws DataNormalizationException {
+            throws DataNormalizationException {
         DataNormalizationOperation<?> current = legacyToNormalized.getRootOperation();
         for (PathArgument arg : normalized.getPathArguments()) {
             current = current.getChild(arg);
@@ -234,10 +236,9 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
     }
 
     private static final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> toDOMEntry(
-            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key,
-            final NormalizedNode<?, ?> value) {
-        return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(
-                key, value);
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key, final NormalizedNode<?, ?> value) {
+        return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(key,
+                value);
     }
 
     public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
@@ -263,7 +264,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     public Optional<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>> toBinding(
             final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized)
-                    throws DeserializationException {
+            throws DeserializationException {
         Optional<InstanceIdentifier<? extends DataObject>> potentialPath = toBinding(normalized.getKey());
         if (potentialPath.isPresent()) {
             InstanceIdentifier<? extends DataObject> bindingPath = potentialPath.get();
@@ -290,27 +291,155 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
         if (isAugmentationIdentifier(processed)) {
             return processed;
         }
-        // Here we employ small trick - DataNormalizer injects augmentation
-        // identifier if child is
-        // also part of the path (since using a child we can safely identify
-        // augmentation)
-        // so, we scan augmentation for children add it to path
-        // and use original algorithm, then shorten it to last augmentation
-        for (@SuppressWarnings("rawtypes")
-        Class augChild : getAugmentationChildren(augPath.getTargetType())) {
+        Optional<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> additionalSerialized;
+        additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed);
+
+        if (additionalSerialized.isPresent()) {
+            return additionalSerialized.get();
+        }
+        additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed);
+        if (additionalSerialized.isPresent()) {
+            return additionalSerialized.get();
+        }
+        throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath);
+    }
+
+    /**
+     * Tries to find correct augmentation identifier using children leafs
+     *
+     * This method uses normalized Instance Identifier of parent node to fetch
+     * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about
+     * augmentation namespace, specificly, in which module it was defined.
+     *
+     * Then it uses it to filter all available augmentations for parent by
+     * module. After that it walks augmentations in particular module and
+     * pick-up first which at least one leaf name matches supplied augmentation.
+     * We could do this safely since YANG explicitly states that no any existing
+     * augmentations must differ in leaf fully qualified names.
+     *
+     *
+     * @param augPath
+     *            Binding Aware Path which ends with augment
+     * @param parentPath
+     *            Processed path
+     * @return
+     */
+    private Optional<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toNormalizedAugmentedUsingChildLeafs(
+            final InstanceIdentifier<?> augPath,
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) {
+        try {
+            DataNormalizationOperation<?> parentOp = legacyToNormalized.getOperation(parentPath);
+            if(!parentOp.getDataSchemaNode().isPresent()) {
+                return Optional.absent();
+            }
+            DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get();
+            if (parentSchema instanceof AugmentationTarget) {
+                Set<AugmentationSchema> augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations();
+                LOG.info("Augmentations for {}, {}", augPath, augmentations);
+                Optional<AugmentationSchema> schema = findAugmentation(augPath.getTargetType(), augmentations);
+                if (schema.isPresent()) {
+                    AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation
+                            .augmentationIdentifierFrom(schema.get());
+                    return Optional.of(parentPath.node(augmentationIdentifier));
+                }
+            }
+        } catch (DataNormalizationException e) {
+            throw new IllegalArgumentException(e);
+        }
+        return Optional.absent();
+    }
+
+    /**
+     * Creates instance identifier for augmentation child, tries to serialize it
+     * Instance Identifier is then shortened to last augmentation.
+     *
+     * This is for situations, where underlying codec is implementing hydrogen
+     * style DOM APIs (which did not supported {@link AugmentationIdentifier}.)
+     *
+     * @param augPath
+     * @param parentPath
+     *            Path to parent node
+     * @return
+     */
+    @SuppressWarnings("rawtypes")
+    private Optional<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toNormalizedAugmentedUsingChildContainers(
+            final InstanceIdentifier<?> augPath,
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) {
+        for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) {
             @SuppressWarnings("unchecked")
             InstanceIdentifier<?> childPath = augPath.child(augChild);
             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = toNormalizedImpl(childPath);
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation(normalized);
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation(
+                    normalized, parentPath);
             if (potentialDiscovered != null) {
-                return potentialDiscovered;
+                return Optional.of(potentialDiscovered);
+            }
+        }
+        return Optional.absent();
+    }
+
+    private Optional<AugmentationSchema> findAugmentation(final Class targetType,
+            final Set<AugmentationSchema> augmentations) {
+        YangModuleInfo moduleInfo;
+        try {
+            moduleInfo = BindingReflections.getModuleInfo(targetType);
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+        Iterable<AugmentationSchema> filtered = filteredByModuleInfo(augmentations,
+                BindingReflections.getModuleQName(moduleInfo).getModule());
+        filtered.toString();
+        Set<String> targetTypeGetters = getYangModeledGetters(targetType);
+        for (AugmentationSchema schema : filtered) {
+            for (DataSchemaNode child : schema.getChildNodes()) {
+                String getterName = "get" + BindingMapping.getClassName(child.getQName());
+                if (targetTypeGetters.contains(getterName)) {
+                    return Optional.of(schema);
+                }
             }
         }
-        return processed;
+        return Optional.absent();
+    }
+
+    private static Iterable<AugmentationSchema> filteredByModuleInfo(final Iterable<AugmentationSchema> augmentations,
+            final QNameModule module) {
+        return Iterables.filter(augmentations, new Predicate<AugmentationSchema>() {
+            @Override
+            public boolean apply(final AugmentationSchema schema) {
+                final Set<DataSchemaNode> childNodes = schema.getChildNodes();
+                return !schema.getChildNodes().isEmpty()
+                        && module.equals(Iterables.get(childNodes, 0).getQName().getModule());
+            }
+        });
+    }
+
+    public static final Set<String> getYangModeledGetters(final Class<?> targetType) {
+        HashSet<String> ret = new HashSet<String>();
+        for (Method method : targetType.getMethods()) {
+            if (isYangModeledGetter(method)) {
+                ret.add(method.getName());
+            }
+        }
+        return ret;
+    }
+
+    /**
+     *
+     * Returns true if supplied method represent getter for YANG modeled value
+     *
+     * @param method
+     *            Method to be tested
+     * @return true if method represent getter for YANG Modeled value.
+     */
+    private static final boolean isYangModeledGetter(final Method method) {
+        return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface")
+                && method.getName().startsWith("get") && method.getParameterTypes().length == 0;
     }
 
     private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier shortenToLastAugmentation(
-            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) {
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized,
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier parentPath) {
+        int parentSize = Iterables.size(parentPath.getPathArguments());
         int position = 0;
         int foundPosition = -1;
         for (PathArgument arg : normalized.getPathArguments()) {
@@ -319,7 +448,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
                 foundPosition = position;
             }
         }
-        if (foundPosition > 0) {
+        if (foundPosition > 0 && foundPosition > parentSize) {
             Iterable<PathArgument> shortened = Iterables.limit(normalized.getPathArguments(), foundPosition);
             return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(shortened);
         }
@@ -348,62 +477,6 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
         return normalized;
     }
 
-    @SuppressWarnings("unchecked")
-    private Iterable<Class<? extends DataObject>> getAugmentationChildren(final Class<?> targetType) {
-        List<Class<? extends DataObject>> ret = new LinkedList<>();
-        for (Method method : targetType.getMethods()) {
-            Class<?> entity = getYangModeledType(method);
-            if (entity != null) {
-                ret.add((Class<? extends DataObject>) entity);
-            }
-        }
-        return ret;
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private Class<? extends DataObject> getYangModeledType(final Method method) {
-        if (method.getName().equals("getClass") || !method.getName().startsWith("get")
-                || method.getParameterTypes().length > 0) {
-            return null;
-        }
-
-        Class<?> returnType = method.getReturnType();
-        if (DataContainer.class.isAssignableFrom(returnType)) {
-            return (Class) returnType;
-        } else if (List.class.isAssignableFrom(returnType)) {
-            try {
-                return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
-                        new Supplier<Class>() {
-                    @Override
-                    public Class get() {
-                        Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
-                                .getGenericReturnType());
-                        if (listResult instanceof Class
-                                && DataObject.class.isAssignableFrom((Class) listResult)) {
-                            return (Class<?>) listResult;
-                        }
-                        return null;
-                    }
-
-                });
-            } catch (Exception e) {
-                LOG.debug("Could not get YANG modeled entity for {}", method, e);
-                return null;
-            }
-
-        }
-        return null;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private static InstanceIdentifier<?> toWildcarded(final InstanceIdentifier<?> orig) {
-        List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument> wildArgs = new LinkedList<>();
-        for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : orig.getPathArguments()) {
-            wildArgs.add(new Item(arg.getType()));
-        }
-        return InstanceIdentifier.create(wildArgs);
-    }
-
     private static boolean isAugmentation(final Class<? extends DataObject> type) {
         return Augmentation.class.isAssignableFrom(type);
     }
@@ -418,26 +491,26 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     private static int getAugmentationCount(final InstanceIdentifier<?> potential) {
         int count = 0;
-        for(org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
-            if(isAugmentation(arg.getType())) {
+        for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
+            if (isAugmentation(arg.getType())) {
                 count++;
             }
-
         }
         return count;
     }
 
     private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potential) {
         int count = 0;
-        for(PathArgument arg : potential.getPathArguments()) {
-            if(arg instanceof AugmentationIdentifier) {
+        for (PathArgument arg : potential.getPathArguments()) {
+            if (arg instanceof AugmentationIdentifier) {
                 count++;
             }
         }
         return count;
     }
 
-    public Function<Optional<NormalizedNode<?, ?>>, Optional<DataObject>>  deserializeFunction(final InstanceIdentifier<?> path) {
+    public Function<Optional<NormalizedNode<?, ?>>, Optional<DataObject>> deserializeFunction(
+            final InstanceIdentifier<?> path) {
         return new DeserializeFunction(this, path);
     }
 
@@ -475,7 +548,8 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
     /**
      * Returns an default object according to YANG schema for supplied path.
      *
-     * @param path DOM Path
+     * @param path
+     *            DOM Path
      * @return Node with defaults set on.
      */
     public NormalizedNode<?, ?> getDefaultNodeFor(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path) {
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/BindingNormalizedCodecTest.java
new file mode 100644 (file)
index 0000000..6b05b10
--- /dev/null
@@ -0,0 +1,58 @@
+package org.opendaylight.controller.md.sal.binding.impl.test;
+
+import static org.junit.Assert.assertTrue;
+import javassist.ClassPool;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.md.sal.binding.test.AbstractSchemaAwareTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeLeafOnlyAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest {
+
+    private static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<TopLevelList> BA_TOP_LEVEL_LIST = InstanceIdentifier
+            .builder(Top.class).child(TopLevelList.class, TOP_FOO_KEY).toInstance();
+    private static final InstanceIdentifier<TreeLeafOnlyAugment> BA_TREE_LEAF_ONLY = BA_TOP_LEVEL_LIST.augmentation(TreeLeafOnlyAugment.class);
+    private static final InstanceIdentifier<TreeComplexUsesAugment> BA_TREE_COMPLEX_USES = BA_TOP_LEVEL_LIST.augmentation(TreeComplexUsesAugment.class);
+    private static final QName SIMPLE_VALUE_QNAME = QName.create(TreeComplexUsesAugment.QNAME, "simple-value");
+
+
+    private RuntimeGeneratedMappingServiceImpl mappingService;
+    private BindingToNormalizedNodeCodec codec;
+
+    @Override
+    protected void setupWithSchema(final SchemaContext context) {
+        mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+        codec = new BindingToNormalizedNodeCodec(mappingService);
+        mappingService.onGlobalContextUpdated(context);
+        codec.onGlobalContextUpdated(context);
+    };
+
+    @Test
+    public void testComplexAugmentationSerialization() {
+
+        PathArgument lastArg = codec.toNormalized(BA_TREE_COMPLEX_USES).getLastPathArgument();
+        assertTrue(lastArg instanceof AugmentationIdentifier);
+    }
+
+
+    @Test
+    public void testLeafOnlyAugmentationSerialization() {
+
+        PathArgument leafOnlyLastArg = codec.toNormalized(BA_TREE_LEAF_ONLY).getLastPathArgument();
+        assertTrue(leafOnlyLastArg instanceof AugmentationIdentifier);
+        assertTrue(((AugmentationIdentifier) leafOnlyLastArg).getPossibleChildNames().contains(SIMPLE_VALUE_QNAME));
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java
new file mode 100644 (file)
index 0000000..05bc857
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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.md.sal.binding.impl.test;
+import static org.junit.Assert.assertFalse;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertContains;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertEmpty;
+import static org.opendaylight.controller.md.sal.binding.test.AssertCollections.assertNotContains;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_BAR_KEY;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.TOP_FOO_KEY;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.top;
+import static org.opendaylight.controller.md.sal.test.model.util.ListsBindingUtils.topLevelList;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataChangeListenerTest;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ *
+ * This testsuite tests explanation for data change scope and data modifications
+ * which were described in
+ * https://lists.opendaylight.org/pipermail/controller-dev/2014-July/005541.html
+ *
+ *
+ */
+public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListenerTest{
+
+    private static final InstanceIdentifier<Top> TOP = InstanceIdentifier.create(Top.class);
+    private static final InstanceIdentifier<TopLevelList> WILDCARDED = TOP.child(TopLevelList.class);
+    private static final InstanceIdentifier<TopLevelList> TOP_FOO = TOP.child(TopLevelList.class, TOP_FOO_KEY);
+    private static final InstanceIdentifier<TopLevelList> TOP_BAR = TOP.child(TopLevelList.class, TOP_BAR_KEY);
+
+
+    @Override
+    protected void setupWithDataBroker(final DataBroker dataBroker) {
+        WriteTransaction initialTx = dataBroker.newWriteOnlyTransaction();
+        initialTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_FOO_KEY)));
+        assertCommit(initialTx.commit());
+    }
+
+    @Test
+    public void replaceTopNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
+        assertCommit(writeTx.commit());
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> top = topListener.event();
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> all = allListener.event();
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> foo = fooListener.event();
+        AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> bar = barListener.event();
+
+        // Listener for TOP element
+        assertContains(top.getOriginalData(), TOP,TOP_FOO);
+        assertContains(top.getCreatedData(), TOP_BAR);
+        assertContains(top.getUpdatedData(), TOP);
+        assertContains(top.getRemovedPaths(), TOP_FOO);
+
+        /*
+         *  Listener for all list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertContains(all.getOriginalData(), TOP_FOO);
+        assertContains(all.getCreatedData(), TOP_BAR);
+        assertEmpty(all.getUpdatedData());
+        assertContains(all.getRemovedPaths(), TOP_FOO);
+
+
+        /*
+         *  Listener for all Foo item
+         *
+         *  This one should see only Foo item removed
+         */
+        assertContains(foo.getOriginalData(), TOP_FOO);
+        assertEmpty(foo.getCreatedData());
+        assertEmpty(foo.getUpdatedData());
+        assertContains(foo.getRemovedPaths(), TOP_FOO);
+
+        /*
+         *  Listener for bar list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertEmpty(bar.getOriginalData());
+        assertContains(bar.getCreatedData(), TOP_BAR);
+        assertEmpty(bar.getUpdatedData());
+        assertEmpty(bar.getRemovedPaths());
+    }
+
+    @Test
+    public void mergeTopNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.merge(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
+        assertCommit(writeTx.commit());
+
+        verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+    }
+
+    @Test
+    public void putTopBarNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.put(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
+        assertCommit(writeTx.commit());
+
+        verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+    }
+
+    @Test
+    public void mergeTopBarNodeSubtreeListeners() {
+        TestListener topListener = createListener(CONFIGURATION, TOP, DataChangeScope.SUBTREE);
+        TestListener allListener = createListener(CONFIGURATION, WILDCARDED, DataChangeScope.SUBTREE);
+        TestListener fooListener = createListener(CONFIGURATION, TOP_FOO, DataChangeScope.SUBTREE);
+        TestListener barListener = createListener(CONFIGURATION, TOP_BAR, DataChangeScope.SUBTREE);
+
+        ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
+        writeTx.merge(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
+        assertCommit(writeTx.commit());
+
+        verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
+    }
+
+    private void verifyBarOnlyAdded(final TestListener top, final TestListener all, final TestListener foo,
+            final TestListener bar) {
+
+        assertFalse(foo.hasEvent());
+
+        // Listener for TOP element
+        assertContains(top.event().getOriginalData(), TOP);
+        assertNotContains(top.event().getOriginalData(),TOP_FOO);
+        assertContains(top.event().getCreatedData(), TOP_BAR);
+        assertContains(top.event().getUpdatedData(), TOP);
+        assertEmpty(top.event().getRemovedPaths());
+
+        /*
+         *  Listener for all list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertEmpty(all.event().getOriginalData());
+        assertContains(all.event().getCreatedData(), TOP_BAR);
+        assertEmpty(all.event().getUpdatedData());
+        assertEmpty(all.event().getRemovedPaths());
+
+        /*
+         *  Listener for all Foo item
+         *
+         *  Foo Listener should not have foo event
+         */
+        assertFalse(foo.hasEvent());
+
+        /*
+         *  Listener for bar list items
+         *
+         *  Updated should be empty, since no list item was
+         *  updated, items were only removed and added
+         */
+        assertEmpty(bar.event().getOriginalData());
+        assertContains(bar.event().getCreatedData(), TOP_BAR);
+        assertEmpty(bar.event().getUpdatedData());
+        assertEmpty(bar.event().getRemovedPaths());
+    }
+
+}
index ad6e1a77cea9c5294852fe7524c5ef6606c65d95..43e951423c0a2bfdecef87969abd01c51816d28e 100644 (file)
@@ -12,42 +12,29 @@ import static org.junit.Assert.assertEquals;
 import java.util.concurrent.ExecutionException;
 
 import org.junit.Test;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 
-public class WriteTransactionTest extends AbstractDataServiceTest {
+public class WriteTransactionTest extends AbstractDataBrokerTest {
 
-    private DataBroker dataBroker;
-
-    private static final InstanceIdentifier<Nodes> NODES_PATH = InstanceIdentifier.create(Nodes.class);
-
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId("foo"));
-
-    private static final InstanceIdentifier<Node> NODE_PATH = NODES_PATH.child(Node.class, NODE_KEY);
-
-    @Override
-    public void setUp() {
-        super.setUp();
-
-        dataBroker = testContext.getDataBroker();
-    }
+    private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
+    private static final TopLevelListKey TOP_LIST_KEY = new TopLevelListKey("foo");
+    private static final InstanceIdentifier<TopLevelList> NODE_PATH = TOP_PATH.child(TopLevelList.class, TOP_LIST_KEY);
 
     @Test
     public void test() throws InterruptedException, ExecutionException {
-        WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
-        writeTx.put(LogicalDatastoreType.OPERATIONAL, NODES_PATH, new NodesBuilder().build());
-        writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new NodeBuilder().setKey(NODE_KEY).build());
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, TOP_PATH, new TopBuilder().build());
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new TopLevelListBuilder().setKey(TOP_LIST_KEY).build());
         assertEquals(TransactionStatus.COMMITED, writeTx.commit().get().getResult());
     }
 
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java
new file mode 100644 (file)
index 0000000..7f23ac2
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.md.sal.binding.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class AbstractDataBrokerTest extends AbstractSchemaAwareTest {
+
+    private DataBrokerTestCustomizer testCustomizer;
+    private DataBroker dataBroker;
+    private DOMDataBroker domBroker;
+
+
+    @Override
+    protected void setupWithSchema(final SchemaContext context) {
+        testCustomizer = createDataBrokerTestCustomizer();
+        dataBroker = testCustomizer.createDataBroker();
+        domBroker = testCustomizer.createDOMDataBroker();
+        testCustomizer.updateSchema(context);
+        setupWithDataBroker(dataBroker);
+    }
+
+    protected void setupWithDataBroker(final DataBroker dataBroker) {
+        // Intentionally left No-op, subclasses may customize it
+    }
+
+   protected DataBrokerTestCustomizer createDataBrokerTestCustomizer() {
+        return new DataBrokerTestCustomizer();
+    }
+
+    public DataBroker getDataBroker() {
+        return dataBroker;
+    }
+
+    public DOMDataBroker getDomBroker() {
+        return domBroker;
+    }
+
+    protected static final void assertCommit(final ListenableFuture<RpcResult<TransactionStatus>> commit) {
+        try {
+            assertEquals(TransactionStatus.COMMITED,commit.get(500, TimeUnit.MILLISECONDS).getResult());
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataChangeListenerTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataChangeListenerTest.java
new file mode 100644 (file)
index 0000000..7742f37
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.md.sal.binding.test;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+public abstract class AbstractDataChangeListenerTest extends AbstractDataBrokerTest {
+
+    protected static final class TestListener implements DataChangeListener {
+
+        private final SettableFuture<AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject>> event;
+        private boolean capture = false;
+
+        private TestListener() {
+            event = SettableFuture.create();
+        }
+
+        @Override
+        public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> arg) {
+            if (capture) {
+                event.set(arg);
+            }
+        }
+
+        public AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event() {
+            try {
+                return event.get(500, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException | TimeoutException | ExecutionException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        public boolean hasEvent() {
+            return event.isDone();
+        }
+
+        public void startCapture() {
+            this.capture = true;
+        }
+    }
+
+    protected final TestListener createListener(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
+            final DataChangeScope scope) {
+        TestListener listener = new TestListener();
+        getDataBroker().registerDataChangeListener(store, path, listener, scope);
+        listener.startCapture();
+        return listener;
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractSchemaAwareTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractSchemaAwareTest.java
new file mode 100644 (file)
index 0000000..78febb5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.md.sal.binding.test;
+
+import org.junit.Before;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public abstract class AbstractSchemaAwareTest  {
+
+    private Iterable<YangModuleInfo> moduleInfos;
+    private SchemaContext schemaContext;
+
+
+    protected Iterable<YangModuleInfo> getModuleInfos() {
+        return BindingReflections.loadModuleInfos();
+    }
+
+
+    @Before
+    public final void setup() {
+        moduleInfos = getModuleInfos();
+        ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
+        moduleContext.addModuleInfos(moduleInfos);
+        schemaContext = moduleContext.tryToCreateSchemaContext().get();
+        setupWithSchema(schemaContext);
+    }
+
+    /**
+     * Setups test with Schema context.
+     * This method is called before {@link #setupWithSchemaService(SchemaService)}
+     *
+     * @param context
+     */
+    protected abstract void setupWithSchema(SchemaContext context);
+
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AssertCollections.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AssertCollections.java
new file mode 100644 (file)
index 0000000..25b91bc
--- /dev/null
@@ -0,0 +1,42 @@
+package org.opendaylight.controller.md.sal.binding.test;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.junit.Assert;
+
+public class AssertCollections {
+
+    public static void assertEmpty(final Collection<?> set) {
+        Assert.assertTrue(set.isEmpty());
+    }
+
+    public static void assertEmpty(final Map<?,?> set) {
+        Assert.assertTrue(set.isEmpty());
+    }
+
+    public static void assertContains(final Collection<?> set, final Object... values) {
+        for (Object key : values) {
+            Assert.assertTrue(set.contains(key));
+        }
+
+    }
+
+    public static void assertNotContains(final Collection<?> set, final Object... values) {
+        for (Object key : values) {
+            Assert.assertFalse(set.contains(key));
+        }
+    }
+
+    public static void assertContains(final Map<?,?> map, final Object... values) {
+        for (Object key : values) {
+            Assert.assertTrue(map.containsKey(key));
+        }
+    }
+
+    public static void assertNotContains(final Map<?,?> map, final Object... values) {
+        for (Object key : values) {
+            Assert.assertFalse(map.containsKey(key));
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java
new file mode 100644 (file)
index 0000000..79aa6b6
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.md.sal.binding.test;
+
+import javassist.ClassPool;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.sal.binding.test.util.MockSchemaService;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class DataBrokerTestCustomizer {
+
+    private DOMDataBroker domDataBroker;
+    private final RuntimeGeneratedMappingServiceImpl mappingService;
+    private final MockSchemaService schemaService;
+    private ImmutableMap<LogicalDatastoreType, DOMStore> datastores;
+
+    public ImmutableMap<LogicalDatastoreType, DOMStore> createDatastores() {
+        return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
+                .put(LogicalDatastoreType.OPERATIONAL, createOperationalDatastore())
+                .put(LogicalDatastoreType.CONFIGURATION,createConfigurationDatastore())
+                .build();
+    }
+
+    public DataBrokerTestCustomizer() {
+        schemaService = new MockSchemaService();
+        mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+    }
+
+    public DOMStore createConfigurationDatastore() {
+        InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG", MoreExecutors.sameThreadExecutor());
+        schemaService.registerSchemaServiceListener(store);
+        return store;
+    }
+
+    public DOMStore createOperationalDatastore() {
+        InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", MoreExecutors.sameThreadExecutor());
+        schemaService.registerSchemaServiceListener(store);
+        return store;
+    }
+
+    public DOMDataBroker createDOMDataBroker() {
+        return new DOMDataBrokerImpl(getDatastores(), getCommitCoordinatorExecutor());
+    }
+
+    public ListeningExecutorService getCommitCoordinatorExecutor() {
+        return MoreExecutors.sameThreadExecutor();
+    }
+
+    public DataBroker createDataBroker() {
+        return new ForwardedBindingDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService());
+    }
+
+    private SchemaService getSchemaService() {
+        return schemaService;
+    }
+
+    private BindingIndependentMappingService getMappingService() {
+        return mappingService;
+    }
+
+    private DOMDataBroker getDOMDataBroker() {
+        if(domDataBroker == null) {
+            domDataBroker = createDOMDataBroker();
+        }
+        return domDataBroker;
+    }
+
+    private ImmutableMap<LogicalDatastoreType, DOMStore> getDatastores() {
+        if(datastores == null) {
+            datastores = createDatastores();
+        }
+        return datastores;
+    }
+
+    public void updateSchema(final SchemaContext ctx) {
+        schemaService.changeSchema(ctx);
+        mappingService.onGlobalContextUpdated(ctx);
+    }
+
+}
index 6c80f4d7394947cd34af1aa3eedb305dc2f99113..591e07d00440465f1bc6763d8ef4ef1508d9191c 100644 (file)
@@ -7,28 +7,21 @@
  */
 package org.opendaylight.controller.sal.binding.test;
 
-import org.junit.After;
 import org.junit.Before;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
 import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 
+@SuppressWarnings("deprecation")
 public abstract class AbstractDataServiceTest {
-    private static Logger log = LoggerFactory.getLogger(AbstractDataServiceTest.class);
 
     protected org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
     protected DataProviderService baDataService;
     protected BindingIndependentMappingService mappingService;
-    private DataStoreStatsWrapper dataStoreStats;
-    protected DataStore dataStore;
     protected BindingTestContext testContext;
 
     @Before
@@ -42,18 +35,10 @@ public abstract class AbstractDataServiceTest {
 
         baDataService = testContext.getBindingDataBroker();
         biDataService = testContext.getDomDataBroker();
-        dataStore = testContext.getDomDataStore();
         mappingService = testContext.getBindingToDomMappingService();
     }
 
     protected boolean getStartWithSchema() {
         return true;
     }
-
-    @After
-    public void afterTest() {
-
-        testContext.logDataStoreStatistics();
-
-    }
 }
index 08c5d061dc832d47cdcffe991cacc2ddb25b6332..c58e258e8b64daa1151a88d1153aac3571d813ea 100644 (file)
@@ -11,10 +11,12 @@ import java.util.concurrent.ExecutorService;
 
 import javassist.ClassPool;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 
+@Beta
 public class BindingBrokerTestFactory {
 
     private static final ClassPool CLASS_POOL = ClassPool.getDefault();
index 8ba709ad30c461e5b69c50b0d34c9b2d78579fbb..f5e902c775a9320857e9665ff79792f71b0a628c 100644 (file)
@@ -9,9 +9,6 @@ package org.opendaylight.controller.sal.binding.test.util;
 
 import static com.google.common.base.Preconditions.checkState;
 
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Future;
 
@@ -41,36 +38,33 @@ import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.controller.sal.core.api.data.DataStore;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
-import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
-import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.reflections.Reflections;
-import org.reflections.scanners.ResourcesScanner;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Predicate;
+import com.google.common.annotations.Beta;
 import com.google.common.collect.ClassToInstanceMap;
 import com.google.common.collect.ImmutableClassToInstanceMap;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.MutableClassToInstanceMap;
 import com.google.common.util.concurrent.ListeningExecutorService;
 
+@Beta
 public class BindingTestContext implements AutoCloseable {
 
     public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
@@ -86,14 +80,9 @@ public class BindingTestContext implements AutoCloseable {
     private BindingIndependentConnector baConnectImpl;
 
     private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
+    @SuppressWarnings("deprecation")
     private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataLegacyBroker;
     private BrokerImpl biBrokerImpl;
-    private HashMapDataStore rawDataStore;
-    private SchemaAwareDataStoreAdapter schemaAwareDataStore;
-    private DataStoreStatsWrapper dataStoreStats;
-    private DataStore dataStore;
-
-    private final boolean dataStoreStatisticsEnabled = false;
 
     private final ListeningExecutorService executor;
     private final ClassPool classPool;
@@ -108,6 +97,7 @@ public class BindingTestContext implements AutoCloseable {
 
     private BackwardsCompatibleDataBroker biCompatibleBroker;
 
+    @SuppressWarnings("deprecation")
     private DataProviderService baData;
 
     private DOMDataBroker newDOMDataBroker;
@@ -128,25 +118,6 @@ public class BindingTestContext implements AutoCloseable {
         this.startWithSchema = startWithSchema;
     }
 
-    @Deprecated
-    public void startDomDataStore() {
-        checkState(dataStore == null, "DataStore already started.");
-        checkState(biDataImpl != null, "Dom Data Broker not present");
-        rawDataStore = new HashMapDataStore();
-        schemaAwareDataStore = new SchemaAwareDataStoreAdapter();
-        schemaAwareDataStore.changeDelegate(rawDataStore);
-        if (dataStoreStatisticsEnabled) {
-            dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore);
-            dataStore = dataStoreStats;
-        } else {
-            dataStore = schemaAwareDataStore;
-        }
-        mockSchemaService.registerSchemaServiceListener(schemaAwareDataStore);
-        biDataImpl.registerConfigurationReader(TREE_ROOT, dataStore);
-        biDataImpl.registerOperationalReader(TREE_ROOT, dataStore);
-        biDataImpl.registerCommitHandler(TREE_ROOT, dataStore);
-    }
-
     public void startDomDataBroker() {
         checkState(executor != null, "Executor needs to be set");
         biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
@@ -213,6 +184,7 @@ public class BindingTestContext implements AutoCloseable {
 
     private ProviderSession createMockContext() {
 
+        @SuppressWarnings("deprecation")
         final ClassToInstanceMap<BrokerService> domBrokerServices = ImmutableClassToInstanceMap
                 .<BrokerService> builder()
                 //
@@ -277,47 +249,14 @@ public class BindingTestContext implements AutoCloseable {
         mockSchemaService.registerSchemaServiceListener(mappingServiceImpl);
     }
 
-    public void updateYangSchema(final String[] files) {
-        mockSchemaService.changeSchema(getContext(files));
+    private void updateYangSchema(final ImmutableSet<YangModuleInfo> moduleInfos) {
+        mockSchemaService.changeSchema(getContext(moduleInfos));
     }
 
-    public static String[] getAllYangFilesOnClasspath() {
-        Predicate<String> predicate = new Predicate<String>() {
-            @Override
-            public boolean apply(final String input) {
-                return input.endsWith(".yang");
-            }
-        };
-        Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner());
-        Set<String> result = reflection.getResources(predicate);
-        return result.toArray(new String[result.size()]);
-    }
-
-    private static SchemaContext getContext(final String[] yangFiles) {
-        ClassLoader loader = BindingTestContext.class.getClassLoader();
-        List<InputStream> streams = new ArrayList<>();
-        for (String string : yangFiles) {
-            InputStream stream = loader.getResourceAsStream(string);
-            streams.add(stream);
-        }
-        YangParserImpl parser = new YangParserImpl();
-        Set<Module> modules = parser.parseYangModelsFromStreams(streams);
-        return parser.resolveSchemaContext(modules);
-    }
-
-    public void startLegacy() {
-        startBindingDataBroker();
-        startBindingNotificationBroker();
-        startBindingBroker();
-        startDomDataBroker();
-        startDomDataStore();
-        startDomBroker();
-        startDomMountPoint();
-        startBindingToDomMappingService();
-        startForwarding();
-        if (startWithSchema) {
-            loadYangSchemaFromClasspath();
-        }
+    private SchemaContext getContext(final ImmutableSet<YangModuleInfo> moduleInfos) {
+        ModuleInfoBackedContext ctx = ModuleInfoBackedContext.create();
+        ctx.addModuleInfos(moduleInfos);
+        return ctx.tryToCreateSchemaContext().get();
     }
 
     public void start() {
@@ -363,44 +302,24 @@ public class BindingTestContext implements AutoCloseable {
     }
 
     public void loadYangSchemaFromClasspath() {
-        String[] files = getAllYangFilesOnClasspath();
-        updateYangSchema(files);
+        ImmutableSet<YangModuleInfo> moduleInfos = BindingReflections.loadModuleInfos();
+        updateYangSchema(moduleInfos);
     }
 
+    @SuppressWarnings("deprecation")
     public DataProviderService getBindingDataBroker() {
         return baData;
     }
 
+    @SuppressWarnings("deprecation")
     public org.opendaylight.controller.sal.core.api.data.DataProviderService getDomDataBroker() {
         return biDataLegacyBroker;
     }
 
-    public DataStore getDomDataStore() {
-        return dataStore;
-    }
-
     public BindingIndependentMappingService getBindingToDomMappingService() {
         return mappingServiceImpl;
     }
 
-    public void logDataStoreStatistics() {
-        if (dataStoreStats == null) {
-            return;
-        }
-
-        LOG.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
-                dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(),
-                dataStoreStats.getConfigurationReadAverageTime());
-
-        LOG.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
-                dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(),
-                dataStoreStats.getOperationalReadAverageTime());
-
-        LOG.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ms AverageTime (ns): {} ms",
-                dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
-                dataStoreStats.getRequestCommitAverageTime());
-    }
-
     public RpcProviderRegistry getBindingRpcRegistry() {
         return baBrokerImpl.getRoot();
     }
index 75d48612b831be05ad4a36ed244c2a6a1ff3db10..bddbc4e95400965da7533b3d66dfee72fa6c3710 100644 (file)
@@ -54,7 +54,6 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
 
         baDataService = testContext.getBindingDataBroker();
         biDataService = testContext.getDomDataBroker();
-        dataStore = testContext.getDomDataStore();
         mappingService = testContext.getBindingToDomMappingService();
     };
 
index dca5200d392687e25493876f945e347d3e394bf4..0bdaf7bf3766736aa76337a1e6e772e036ed0cb5 100644 (file)
@@ -41,9 +41,12 @@ public interface AsyncDataChangeListener<P extends Path<P>, D> extends EventList
      * This initial event will contain all preexisting data as created.
      *
      * <p>
-     * <b>Note</b> that this method may be invoked from a shared thread pool, so
-     * implementations SHOULD NOT perform CPU-intensive operations and they
-     * definitely MUST NOT invoke any potentially blocking operations.
+     * <b>Note</b>: This method may be invoked from a shared thread pool.
+     * <li>Implementations <b>SHOULD NOT</b> perform CPU-intensive operations on the calling thread.
+     * <li>Implementations <b>MUST NOT block the calling thread</b> - to do so could lead to deadlock
+     * scenarios.
+     *
+     *<br>
      *
      * @param change
      *            Data Change Event being delivered.
index 2b9694bed71d87dfb8d48e04024b94f619e5c049..617697710449b32602682802d10dd2022f551ee2 100644 (file)
@@ -10,11 +10,6 @@ package org.opendaylight.controller.md.sal.common.impl.util.compat;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -52,19 +47,31 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 
 public abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
 
     private final T identifier;
+    private final Optional<DataSchemaNode> dataSchemaNode;
 
     @Override
     public T getIdentifier() {
         return identifier;
     };
 
-    protected DataNormalizationOperation(final T identifier) {
+    protected DataNormalizationOperation(final T identifier, final SchemaNode schema) {
         super();
         this.identifier = identifier;
+        if(schema instanceof DataSchemaNode) {
+            this.dataSchemaNode = Optional.of((DataSchemaNode) schema);
+        } else {
+            this.dataSchemaNode = Optional.absent();
+        }
     }
 
     public boolean isMixin() {
@@ -88,10 +95,15 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
     public abstract boolean isLeaf();
 
+    public Optional<DataSchemaNode> getDataSchemaNode() {
+        // FIXME
+        return dataSchemaNode;
+    }
+
     private static abstract class SimpleTypeNormalization<T extends PathArgument> extends DataNormalizationOperation<T> {
 
-        protected SimpleTypeNormalization(final T identifier) {
-            super(identifier);
+        protected SimpleTypeNormalization(final T identifier, final DataSchemaNode potential) {
+            super(identifier,potential);
         }
 
         @Override
@@ -127,8 +139,8 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
     private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
 
-        protected LeafNormalization(final NodeIdentifier identifier) {
-            super(identifier);
+        protected LeafNormalization(final LeafSchemaNode potential) {
+            super(new NodeIdentifier(potential.getQName()),potential);
         }
 
         @Override
@@ -141,7 +153,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
     private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
 
         public LeafListEntryNormalization(final LeafListSchemaNode potential) {
-            super(new NodeWithValue(potential.getQName(), null));
+            super(new NodeWithValue(potential.getQName(), null),potential);
         }
 
         @Override
@@ -160,8 +172,8 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
     private static abstract class CompositeNodeNormalizationOperation<T extends PathArgument> extends
     DataNormalizationOperation<T> {
 
-        protected CompositeNodeNormalizationOperation(final T identifier) {
-            super(identifier);
+        protected CompositeNodeNormalizationOperation(final T identifier, final DataSchemaNode schema) {
+            super(identifier,schema);
         }
 
         @SuppressWarnings({ "rawtypes", "unchecked" })
@@ -226,8 +238,8 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         private final Map<QName, DataNormalizationOperation<?>> byQName;
         private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
 
-        protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
-            super(identifier);
+        protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema, final DataSchemaNode node) {
+            super(identifier,node);
             this.schema = schema;
             this.byArg = new ConcurrentHashMap<>();
             this.byQName = new ConcurrentHashMap<>();
@@ -283,7 +295,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         private final List<QName> keyDefinition;
 
         protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
-            super(identifier, schema);
+            super(identifier, schema,schema);
             keyDefinition = schema.getKeyDefinition();
         }
 
@@ -324,7 +336,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
     private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
 
         protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
-            super(new NodeIdentifier(schema.getQName()), schema);
+            super(new NodeIdentifier(schema.getQName()), schema,schema);
         }
 
         @Override
@@ -342,7 +354,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
     private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
 
         protected ContainerNormalization(final ContainerSchemaNode schema) {
-            super(new NodeIdentifier(schema.getQName()), schema);
+            super(new NodeIdentifier(schema.getQName()),schema, schema);
         }
 
         @Override
@@ -360,8 +372,8 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
     private static abstract class MixinNormalizationOp<T extends PathArgument> extends
     CompositeNodeNormalizationOperation<T> {
 
-        protected MixinNormalizationOp(final T identifier) {
-            super(identifier);
+        protected MixinNormalizationOp(final T identifier, final DataSchemaNode schema) {
+            super(identifier,schema);
         }
 
         @Override
@@ -395,7 +407,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         private final DataNormalizationOperation<?> innerOp;
 
         public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
-            super(new NodeIdentifier(potential.getQName()));
+            super(new NodeIdentifier(potential.getQName()),potential);
             innerOp = new LeafListEntryNormalization(potential);
         }
 
@@ -430,7 +442,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
         public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
             //super();
-            super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
+            super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema),null);
         }
 
         @Override
@@ -479,7 +491,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         private final ListItemNormalization innerNode;
 
         public UnorderedMapMixinNormalization(final ListSchemaNode list) {
-            super(new NodeIdentifier(list.getQName()));
+            super(new NodeIdentifier(list.getQName()),list);
             this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
                     Collections.<QName, Object> emptyMap()), list);
         }
@@ -519,7 +531,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         private final UnkeyedListItemNormalization innerNode;
 
         public UnkeyedListMixinNormalization(final ListSchemaNode list) {
-            super(new NodeIdentifier(list.getQName()));
+            super(new NodeIdentifier(list.getQName()),list);
             this.innerNode = new UnkeyedListItemNormalization(list);
         }
 
@@ -577,7 +589,7 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
         private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
 
         protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
-            super(new NodeIdentifier(schema.getQName()));
+            super(new NodeIdentifier(schema.getQName()),schema);
             ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
             ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder = ImmutableMap.builder();
 
@@ -617,8 +629,8 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
     private static class AnyXmlNormalization extends DataNormalizationOperation<NodeIdentifier> {
 
-        protected AnyXmlNormalization( final NodeIdentifier identifier ) {
-            super( identifier );
+        protected AnyXmlNormalization( final AnyXmlSchemaNode schema) {
+            super( new NodeIdentifier(schema.getQName()), schema);
         }
 
         @Override
@@ -746,13 +758,13 @@ public abstract class DataNormalizationOperation<T extends PathArgument> impleme
 
             return fromListSchemaNode((ListSchemaNode) potential);
         } else if (potential instanceof LeafSchemaNode) {
-            return new LeafNormalization(new NodeIdentifier(potential.getQName()));
+            return new LeafNormalization((LeafSchemaNode) potential);
         } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
             return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
         } else if (potential instanceof LeafListSchemaNode) {
             return fromLeafListSchemaNode((LeafListSchemaNode) potential);
         } else if (potential instanceof AnyXmlSchemaNode) {
-            return new AnyXmlNormalization( new NodeIdentifier(potential.getQName() ) );
+            return new AnyXmlNormalization( (AnyXmlSchemaNode) potential);
         }
         return null;
     }
index 113d3dc9f762ec1f0f2f6d4c7307ae3f04e0d19b..e2a960a67aae708d34a4145479b8797fe535d0d6 100644 (file)
@@ -9,12 +9,6 @@ package org.opendaylight.controller.md.sal.common.impl.util.compat;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicates;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -38,6 +32,12 @@ import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
 public class DataNormalizer {
 
     private final DataNormalizationOperation<?> operation;
@@ -72,6 +72,16 @@ public class DataNormalizer {
         return InstanceIdentifier.create(normalizedArgs.build());
     }
 
+    public DataNormalizationOperation<?> getOperation(final InstanceIdentifier legacy) throws DataNormalizationException {
+        DataNormalizationOperation<?> currentOp = operation;
+        Iterator<PathArgument> arguments = legacy.getPathArguments().iterator();
+
+        while (arguments.hasNext()) {
+            currentOp = currentOp.getChild(arguments.next());
+        }
+        return currentOp;
+    }
+
     public Map.Entry<InstanceIdentifier, NormalizedNode<?, ?>> toNormalized(
             final Map.Entry<InstanceIdentifier, CompositeNode> legacy) {
         return toNormalized(legacy.getKey(), legacy.getValue());
@@ -120,7 +130,7 @@ public class DataNormalizer {
         DataNormalizationOperation<?> currentOp = operation;
         for (PathArgument normalizedArg : normalized.getPathArguments()) {
             currentOp = currentOp.getChild(normalizedArg);
-            if(!currentOp.isMixin()) {
+            if (!currentOp.isMixin()) {
                 legacyArgs.add(normalizedArg);
             }
         }
@@ -134,7 +144,7 @@ public class DataNormalizer {
             return toLegacyFromDataContainer((DataContainerNode<?>) normalizedData);
         } else if (normalizedData instanceof AnyXmlNode) {
             Node<?> value = ((AnyXmlNode) normalizedData).getValue();
-            return value instanceof CompositeNode ? (CompositeNode)value : null;
+            return value instanceof CompositeNode ? (CompositeNode) value : null;
         }
         return null;
     }
@@ -169,7 +179,7 @@ public class DataNormalizer {
         for (NormalizedNode<?, ?> child : node.getValue()) {
             if (child instanceof MixinNode && child instanceof NormalizedNodeContainer<?, ?, ?>) {
                 builder.addAll(toLegacyNodesFromMixin((NormalizedNodeContainer) child));
-            } else ifchild instanceof UnkeyedListNode) {
+            } else if (child instanceof UnkeyedListNode) {
                 builder.addAll(toLegacyNodesFromUnkeyedList((UnkeyedListNode) child));
             } else {
                 addToBuilder(builder, toLegacy(child));
index 8d29b981dc2d8dce784397c25ae99eafa13f27d6..11a0ef211ae2cb20eac661ff789acf9c2e1412eb 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-binding</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>yang-ext</artifactId>
+        </dependency>
     </dependencies>
 
     <artifactId>sal-test-model</artifactId>
diff --git a/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java b/opendaylight/md-sal/sal-test-model/src/main/java/org/opendaylight/controller/md/sal/test/model/util/ListsBindingUtils.java
new file mode 100644 (file)
index 0000000..a0c23ae
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.md.sal.test.model.util;
+
+import java.util.Arrays;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedListKey;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.collect.ImmutableList;
+
+public class ListsBindingUtils {
+
+    private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
+
+    private ListsBindingUtils() {
+        throw new UnsupportedOperationException();
+    }
+
+    public static final TopLevelListKey TOP_FOO_KEY = new TopLevelListKey("foo");
+    public static final TopLevelListKey TOP_BAR_KEY = new TopLevelListKey("bar");
+    public static final ListViaUsesKey USES_ONE_KEY = new ListViaUsesKey("one");
+    public static final ListViaUsesKey USES_TWO_KEY = new ListViaUsesKey("two");
+
+
+    public static InstanceIdentifier<TopLevelList> path(final TopLevelListKey key) {
+        return TOP_PATH.child(TopLevelList.class, key);
+    }
+
+    public static InstanceIdentifier<NestedList> path(final TopLevelListKey top,final NestedListKey nested) {
+        return path(top).child(NestedList.class, nested);
+    }
+
+    public static InstanceIdentifier<ListViaUses> path(final TopLevelListKey top,final ListViaUsesKey uses) {
+        return path(top).augmentation(TreeComplexUsesAugment.class).child(ListViaUses.class, uses);
+    }
+
+    public static <T extends DataObject & Augmentation<TopLevelList>> InstanceIdentifier<T> path(final TopLevelListKey key, final Class<T> augmentation) {
+        return path(key).augmentation(augmentation);
+    }
+
+    public static Top top(final TopLevelList... listItems) {
+        return new TopBuilder().setTopLevelList(Arrays.asList(listItems)).build();
+    }
+
+    public static TopLevelList topLevelList(final TopLevelListKey key) {
+        return new TopLevelListBuilder().setKey(key).build();
+    }
+
+    public static TopLevelList topLevelList(final TopLevelListKey key, final TreeComplexUsesAugment augment) {
+        TopLevelListBuilder builder = new TopLevelListBuilder().setKey(key);
+        builder.addAugmentation(TreeComplexUsesAugment.class, augment);
+        return builder.build();
+    }
+
+    public static TreeComplexUsesAugment complexUsesAugment(final ListViaUsesKey... keys) {
+        ImmutableList.Builder<ListViaUses> listViaUses = ImmutableList.<ListViaUses> builder();
+        for (ListViaUsesKey key : keys) {
+            listViaUses.add(new ListViaUsesBuilder().setKey(key).build());
+        }
+        return new TreeComplexUsesAugmentBuilder().setListViaUses(listViaUses.build()).build();
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-mdsal-augment-test.yang b/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-mdsal-augment-test.yang
new file mode 100644 (file)
index 0000000..ddd7687
--- /dev/null
@@ -0,0 +1,93 @@
+module opendaylight-mdsal-augment-test {
+
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:augment";
+    prefix aug-test;
+
+    import opendaylight-mdsal-list-test {
+        prefix test;
+    }
+    import yang-ext {
+        prefix ext;
+    }
+
+    description
+        "This module contains a collection of YANG augmentations used for
+        some test cases.";
+
+    revision 2014-07-09 {
+        description
+        "Test model for testing data broker with nested lists.";
+    }
+
+    grouping leaf-from-grouping {
+        leaf leaf-from-grouping {
+            type string;
+        }
+    }
+
+    grouping complex-from-grouping {
+        container container-with-uses {
+            uses leaf-from-grouping;
+        }
+        list list-via-uses {
+            key "name";
+            leaf name {
+                type string;
+            }
+        }
+    
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-leaf-only-uses-augment;
+        uses leaf-from-grouping;
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-leaf-only-uses-augment;
+        uses leaf-from-grouping;
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-complex-uses-augment;
+        uses complex-from-grouping;
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-complex-uses-augment;
+        uses complex-from-grouping;
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-leaf-only-augment;
+
+        leaf simple-value {
+            type string;
+        }
+    }
+    
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tree-second-leaf-only-augment;
+
+        leaf second-simple-value {
+            type string;
+        }
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-leaf-only-augment;
+
+        leaf simple-value {
+            type string;
+        }
+    }
+
+    augment "/test:put-top/test:input/test:top-level-list" {
+        ext:augment-identifier rpc-second-leaf-only-augment;
+
+        leaf second-simple-value {
+            type string;
+        }
+    }
+
+}
\ No newline at end of file
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>
index 9825d0eefb791098bf1724d5996c44f881c0da6f..4c0c94ccb82a50d5027b1be6ea23718939cc3a28 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.sal.packet;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
+
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.opendaylight.controller.sal.match.Match;
@@ -156,4 +157,14 @@ public class IEEE8021Q extends Packet {
         match.setField(MatchType.DL_VLAN_PR, this.getPcp());
         match.setField(MatchType.DL_TYPE, this.getEtherType());
     }
+
+    /**
+     * Gets the header size in bits
+     * @return The .1Q header size in bits
+     */
+    @Override
+    public int getHeaderSize() {
+        return 32;
+    }
+
 }