Merge "Handle uncaught exceptions from Clustering Services in HostTracker"
authorChi-Vien Ly <chivly@cisco.com>
Wed, 5 Feb 2014 02:43:13 +0000 (02:43 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 5 Feb 2014 02:43:13 +0000 (02:43 +0000)
110 files changed:
opendaylight/archetypes/odl-model-project/src/main/resources/archetype-resources/pom.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersisterTest.java
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java [deleted file]
opendaylight/config/config-persister-file-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/xml/FileStorageAdapterTest.java
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/md-sal/clustered-data-store/implementation/pom.xml
opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-meter-types.yang
opendaylight/md-sal/model/model-flow-service/src/main/yang/packet-processing.yang
opendaylight/md-sal/model/pom.xml
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/SynchronizedTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMountPointForwarder.java [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedBindingBrokerImpl.java
opendaylight/md-sal/sal-binding-config/pom.xml
opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalProviderInstance.java
opendaylight/md-sal/sal-common-api/pom.xml
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChain.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainClosedException.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend
opendaylight/md-sal/sal-common-util/pom.xml
opendaylight/md-sal/sal-dom-api/pom.xml
opendaylight/md-sal/sal-dom-broker/pom.xml
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataReaderRouter.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangDataOperations.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangSchemaUtils.java
opendaylight/md-sal/sal-netconf-connector/pom.xml
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend
opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang
opendaylight/md-sal/sal-remoterpc-connector/implementation/pom.xml
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/Draft01.java [deleted file]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java [deleted file]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonBasicYangTypesTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIncorrectTopLevelTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata_leaf_list.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata_leaf_list.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module-leaf-list.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster/pom.xml
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImplTest.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml
opendaylight/netconf/ietf-netconf-monitoring/pom.xml
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java
opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/SSHNetconfClientLiveTest.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfDispatcherImplTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.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-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageAggregator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java
opendaylight/netconf/pom.xml
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Match.java
opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerServiceTest.java
opendaylight/protocol_plugins/openflow/src/test/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6ExtensionTest.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/packet/LLDP.java
opendaylight/web/root/src/main/resources/js/lib.js
opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java
opendaylight/web/troubleshoot/src/main/resources/js/page.js

index 70742bd..ebb9302 100644 (file)
@@ -9,8 +9,8 @@
   <properties>\r
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\r
     <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>\r
-    <yang.version>0.6.1</yang.version>\r
-    <yang.codegen.version>0.6.1</yang.codegen.version>\r
+    <yang.version>0.6.2-SNAPSHOT</yang.version>\r
+    <yang.codegen.version>0.6.2-SNAPSHOT</yang.codegen.version>\r
     <bundle.plugin.version>2.3.7</bundle.plugin.version>\r
   </properties>\r
   <scm>\r
index 47b31fb..9d4f838 100644 (file)
@@ -69,7 +69,7 @@
     <enforcer.version>1.3.1</enforcer.version>
     <bundle.plugin.version>2.3.7</bundle.plugin.version>
     <junit.version>4.8.1</junit.version>
-    <yangtools.version>0.6.1</yangtools.version>
+    <yangtools.version>0.6.2-SNAPSHOT</yangtools.version>
     <!--versions for bits of the controller -->
     <controller.version>0.4.2-SNAPSHOT</controller.version>
     <hosttracker.api.version>0.5.2-SNAPSHOT</hosttracker.api.version>
index f833460..bcade93 100644 (file)
@@ -8,12 +8,15 @@
 package org.opendaylight.controller.config.persist.storage.directory.autodetect;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.List;
 import junit.framework.Assert;
 import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.test.PropertiesProviderTest;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 
 public class AutodetectDirectoryPersisterTest {
 
@@ -37,5 +40,52 @@ public class AutodetectDirectoryPersisterTest {
         String snapFromXml = configs.get(1).getConfigSnapshot();
         org.junit.Assert.assertThat(snapFromXml, JUnitMatchers.containsString("<config>xml</config>"));
 
-        Assert.assertEquals(configs.get(0).getCapabilities(), configs.get(1).getCapabilities());    }
+        Assert.assertEquals(configs.get(0).getCapabilities(), configs.get(1).getCapabilities());
+    }
+
+    @Test
+    public void testInvalidXml() throws Exception {
+        File resourcePath = FileTypeTest.getResourceAsFile("/bad_controller.xml.config");
+        File parentFile = resourcePath.getParentFile();
+
+        AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter();
+
+        PropertiesProviderTest pp = new PropertiesProviderTest();
+        pp.addProperty("directoryStorage",parentFile.getPath());
+        AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp);
+        try {
+            List<ConfigSnapshotHolder> configs = persister.loadLastConfigs();
+            fail("An exception of type " + IllegalStateException.class + " was expected");
+        } catch (IllegalStateException ise){
+            String message = ise.getMessage();
+            assertThat(message, JUnitMatchers.containsString("Unable to restore configuration snapshot from "));
+        }
+
+    }
+
+    @Test
+    public void testPersistConfig() throws Exception {
+        File resourcePath = FileTypeTest.getResourceAsFile("/combined/1controller.txt.config");
+        File parentFile = resourcePath.getParentFile();
+
+        AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter();
+
+        PropertiesProviderTest pp = new PropertiesProviderTest();
+        pp.addProperty("directoryStorage",parentFile.getPath());
+        AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp);
+        List<ConfigSnapshotHolder> configs = null;
+        try {
+            configs = persister.loadLastConfigs();
+        } catch (IOException e) {
+            fail("An exception of type " + UnsupportedOperationException.class + " was expected");
+        }
+        Assert.assertEquals(2, configs.size());
+        try {
+            persister.persistConfig(configs.get(0));
+        } catch (UnsupportedOperationException uoe){
+            String message = uoe.getMessage();
+            assertThat(message,JUnitMatchers.containsString("This adapter is read only. Please set readonly=true on class"));
+        }
+    }
+
 }
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config
new file mode 100644 (file)
index 0000000..3f6a337
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability
+        <capability>cap2</capability>
+        <capability>capa a</capability>
+    </required-capabilities>
+    <configuration>
+        <config>xml</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/CapabilityHandler.java
deleted file mode 100644 (file)
index d384df6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2013 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.persist.storage.file.xml.model;
-
-import javax.xml.bind.ValidationEventHandler;
-import javax.xml.bind.annotation.DomHandler;
-import javax.xml.transform.Source;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-import java.io.StringReader;
-import java.io.StringWriter;
-
-class CapabilityHandler implements DomHandler<String, StreamResult> {
-
-    private static final String START_TAG = "<capability>";
-    private static final String END_TAG = "</capability>";
-
-    private StringWriter xmlWriter = new StringWriter();
-
-    public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
-        xmlWriter.getBuffer().setLength(0);
-        return new StreamResult(xmlWriter);
-    }
-
-    public String getElement(StreamResult rt) {
-        String xml = rt.getWriter().toString();
-        int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
-        int endIndex = xml.indexOf(END_TAG);
-        return xml.substring(beginIndex, endIndex);
-    }
-
-    public Source marshal(String n, ValidationEventHandler errorHandler) {
-        try {
-            String xml = START_TAG + n.trim() + END_TAG;
-            StringReader xmlReader = new StringReader(xml);
-            return new StreamSource(xmlReader);
-        } catch(Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-}
index 0e4cce5..5322f63 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.controller.config.persist.storage.file.xml;
 
 import com.google.common.base.Charsets;
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.nio.file.Files;
 import java.util.List;
 import java.util.SortedSet;
@@ -29,6 +31,8 @@ public class FileStorageAdapterTest {
 
     private static int i;
     private File file;
+    private static final String NON_EXISTENT_DIRECTORY = "./nonExistentDir/";
+    private static final String NON_EXISTENT_FILE = "nonExistent.txt";
 
     @Before
     public void setUp() throws Exception {
@@ -39,6 +43,32 @@ public class FileStorageAdapterTest {
         i = 1;
     }
 
+    @Test
+    public void testNewFile() throws Exception {
+        XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
+        PropertiesProviderTest pp = new PropertiesProviderTest();
+        pp.addProperty("fileStorage",NON_EXISTENT_DIRECTORY+NON_EXISTENT_FILE);
+        pp.addProperty("numberOfBackups",Integer.toString(Integer.MAX_VALUE));
+        storage.instantiate(pp);
+
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
+            @Override
+            public String getConfigSnapshot() {
+                return createConfig();
+            }
+
+            @Override
+            public SortedSet<String> getCapabilities() {
+                return createCaps();
+            }
+        };
+        storage.persistConfig(holder);
+
+        storage.persistConfig(holder);
+
+        Assert.assertEquals(storage.toString().replace("\\","/"),"XmlFileStorageAdapter [storage="+NON_EXISTENT_DIRECTORY+NON_EXISTENT_FILE+"]");
+        delete(new File(NON_EXISTENT_DIRECTORY));
+    }
     @Test
     public void testFileAdapter() throws Exception {
         XmlFileStorageAdapter storage = new XmlFileStorageAdapter();
@@ -191,4 +221,12 @@ public class FileStorageAdapterTest {
         return "<config>" + i++ + "</config>";
     }
 
+    private void delete(File f) throws IOException {
+        if (f.isDirectory()) {
+            for (File c : f.listFiles())
+                delete(c);
+        }
+        if (!f.delete())
+            throw new FileNotFoundException("Failed to delete file: " + f);
+    }
 }
index dca781e..28637bc 100644 (file)
          <dependency>
           <groupId>org.opendaylight.yangtools</groupId>
           <artifactId>yang-binding</artifactId>
-          <version>0.6.1</version>
+          <version>${yangtools.version}</version>
          </dependency>
          <dependency>
           <groupId>org.opendaylight.yangtools</groupId>
           <artifactId>binding-type-provider</artifactId>
-          <version>0.6.1</version>
+          <version>${yangtools.version}</version>
          </dependency>
          <dependency>
           <groupId>org.opendaylight.yangtools</groupId>
index 47563b9..1ddfe1c 100644 (file)
@@ -13,7 +13,7 @@ osgi.bundles=\
     reference\:file\:../lib/jersey-server-1.17.jar@2:start
 
 # Netconf startup configuration
-netconf.tcp.address=0.0.0.0
+netconf.tcp.address=127.0.0.1
 netconf.tcp.port=8383
 
 netconf.tcp.client.address=127.0.0.1
index c1e2fec..e6cfee1 100644 (file)
@@ -72,7 +72,7 @@
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.6.1</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index 1686cad..6d14050 100644 (file)
@@ -73,38 +73,46 @@ module opendaylight-meter-types {
         choice band-type {
             case drop {
                 leaf drop-rate {
+                    description "Rate for dropping packets";
                     type uint32;
                 }
                 
                 leaf drop-burst-size {
+                    description "Size of bursts";
                     type uint32;
                 }
             }
 
             case dscp-remark {
                 leaf dscp-remark-rate {
+                    description "Rate for remarking packets";
                     type uint32;
                 }
                 
                 leaf dscp-remark-burst-size {
+                    description "Size of bursts";
                     type uint32;
                 }
                 
                 leaf perc_level {
+                    description "Number of drop precedence level to add";
                     type uint8;
                 }
             }
             
             case experimenter {
                 leaf experimenter-rate {
+                    description "Rate for remarking packets";
                     type uint32;
                 }
                 
                 leaf experimenter-burst-size {
+                    description "Size of bursts";
                     type uint32;
                 }
                 
                 leaf experimenter {
+                    description "Experimenter id";
                     type uint32;
                 }
             }
@@ -118,22 +126,27 @@ module opendaylight-meter-types {
     grouping meter {
         
         leaf flags {
+           description "Meter configuration flags";
            type meter-flags;        
         }
         
         leaf meter-id {
+            description "Meter instance";
             type meter-id;
         }       
         
         leaf barrier {
+            description "If true, barrier message is sent";
             type boolean; 
         }
         
         leaf meter-name {
+            description "Name of meter instance";
             type string;
         }
         
         leaf container-name {
+            description "Name of container";
             type string; 
         }
         
@@ -141,20 +154,24 @@ module opendaylight-meter-types {
             list meter-band-header {
                 key "band-id";
                 leaf band-id {
+                    description "Meter band id";
                     type band-id;
                 }
                 
                 container meter-band-types {
                     leaf flags {
+                        description "Meter band flags";
                         type meter-band-type;
                     }
                 }
             
                 leaf band-rate {
+                    description "Rate for this band";
                     type uint32;
                 }
         
                 leaf band-burst-size {
+                    description "Size of bursts";
                     type uint32;
                 }
                 uses band-type;
index 00ecdba..f3db318 100644 (file)
@@ -8,6 +8,8 @@ module packet-processing {
     import opendaylight-l2-types {prefix types;revision-date "2013-08-27";}
     import opendaylight-match-types {prefix match-type;revision-date "2013-10-26";}
     import opendaylight-table-types {prefix table-type;revision-date "2013-10-26";}
+    import opendaylight-action-types {prefix action-type;revision-date "2013-11-12";}
+
     
     revision "2013-07-09" {
         description "";
@@ -88,7 +90,12 @@ module packet-processing {
                leaf egress {
                        type inv:node-connector-ref;
                }
+               leaf buffer-id {
+                  type uint32;
+            }
+
                uses raw-packet;
+               uses action-type:action-list;
        }
     }
 }
index d31535c..5092995 100644 (file)
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>${yang.codegen.version}</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>yang-binding</artifactId>
-                        <version>${yang.codegen.version}</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index fa6f94b..2f59414 100644 (file)
@@ -8,7 +8,6 @@
         <relativePath>../commons/opendaylight</relativePath>
     </parent>
 
-    <groupId>org.opendaylight.controller</groupId>
     <artifactId>sal-parent</artifactId>
     <version>1.1-SNAPSHOT</version>
     <packaging>pom</packaging>
     </profiles>
 
     <properties>
-        <yangtools.version>0.6.1</yangtools.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
         <!-- Java Versions -->
 
         <!-- Dependency Versions -->
         <slf4j.version>1.7.2</slf4j.version>
-       <yang.codegen.version>${yangtools.version}</yang.codegen.version>
         <guava.version>14.0.1</guava.version>
         <osgi.core.version>5.0.0</osgi.core.version>
         <junit.version>4.8.1</junit.version>
                 <artifactId>maven-jar-plugin</artifactId>
                 <version>2.4</version>
             </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
-                <version>2.8.1</version>
-                <configuration>
-                    <stylesheet>maven</stylesheet>
-                    <failOnError>false</failOnError>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>aggregate</goal>
-                        </goals>
-                        <phase>site</phase>
-                    </execution>
-                </executions>
-            </plugin>
             <plugin>
                 <!-- FIXME: BUG-272: remove this configuration override -->
                 <groupId>org.apache.maven.plugins</groupId>
index cb201c5..c28b03e 100644 (file)
@@ -7,14 +7,17 @@
  */
 package org.opendaylight.controller.sal.binding.api;
 
+import java.util.EventListener;
 import java.util.concurrent.ExecutorService;
 
 import org.opendaylight.controller.md.sal.common.api.notify.NotificationPublishService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.Notification;
 
 public interface NotificationProviderService extends NotificationService, NotificationPublishService<Notification> {
 
+
     /**
      * Deprecated. Use {@link #publish(Notification)}.
      * 
@@ -34,7 +37,8 @@ public interface NotificationProviderService extends NotificationService, Notifi
     /**
      * Publishes a notification.
      * 
-     * @param Notification notification to publish.
+     * @param Notification
+     *            notification to publish.
      * 
      */
     @Override
@@ -46,4 +50,12 @@ public interface NotificationProviderService extends NotificationService, Notifi
      */
     @Override
     void publish(Notification notification, ExecutorService service);
+
+    ListenerRegistration<NotificationInterestListener> registerInterestListener(
+            NotificationInterestListener interestListener);
+
+    public interface NotificationInterestListener extends EventListener {
+
+        void onNotificationSubscribtion(Class<? extends Notification> notificationType);
+    }
 }
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/SynchronizedTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/SynchronizedTransaction.java
new file mode 100644 (file)
index 0000000..d7cb926
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.sal.binding.api.data;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Synchronized wrapper for DataModificationTransaction.
+ * 
+ * To get instance of synchronized wrapper use {@link #from(DataModificationTransaction)}
+ *
+ */
+public final class SynchronizedTransaction implements DataModificationTransaction,Delegator<DataModificationTransaction> {
+
+    private final DataModificationTransaction delegate;
+    
+    private SynchronizedTransaction(DataModificationTransaction delegate) {
+        this.delegate = delegate;
+    }
+
+    /**
+     * Returns synchronized wrapper on supplied transaction.
+     * 
+     * @param transaction Transaction for which synchronized wrapper should be created.
+     * @return Synchronized wrapper over transaction.
+     */
+    public static final SynchronizedTransaction from(DataModificationTransaction transaction) {
+        Preconditions.checkArgument(transaction != null, "Transaction must not be null.");
+        if (transaction instanceof SynchronizedTransaction) {
+            return (SynchronizedTransaction) transaction;
+        }
+        return new SynchronizedTransaction(transaction);
+    }
+
+    @Override
+    public synchronized Map<InstanceIdentifier<? extends DataObject>, DataObject> getCreatedOperationalData() {
+        return delegate.getCreatedOperationalData();
+    }
+
+    @Override
+    public synchronized Map<InstanceIdentifier<? extends DataObject>, DataObject> getCreatedConfigurationData() {
+        return delegate.getCreatedConfigurationData();
+    }
+
+    @Override
+    public synchronized DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
+        return delegate.readOperationalData(path);
+    }
+
+    @Override
+    public synchronized TransactionStatus getStatus() {
+        return delegate.getStatus();
+    }
+
+    @Override
+    public synchronized Map<InstanceIdentifier<? extends DataObject>, DataObject> getUpdatedOperationalData() {
+        return delegate.getUpdatedOperationalData();
+    }
+
+    @Deprecated
+    public synchronized void putRuntimeData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+        delegate.putRuntimeData(path, data);
+    }
+
+    @Override
+    public synchronized Object getIdentifier() {
+        return delegate.getIdentifier();
+    }
+
+    @Override
+    public synchronized DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+        return delegate.readConfigurationData(path);
+    }
+
+    @Override
+    public synchronized Future<RpcResult<TransactionStatus>> commit() {
+        return delegate.commit();
+    }
+
+    @Override
+    public synchronized void putOperationalData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+        delegate.putOperationalData(path, data);
+    }
+
+    @Override
+    public synchronized void putConfigurationData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+        delegate.putConfigurationData(path, data);
+    }
+
+    @Override
+    public synchronized Map<InstanceIdentifier<? extends DataObject>, DataObject> getUpdatedConfigurationData() {
+        return delegate.getUpdatedConfigurationData();
+    }
+
+    @Deprecated
+    public synchronized void removeRuntimeData(InstanceIdentifier<? extends DataObject> path) {
+        delegate.removeRuntimeData(path);
+    }
+
+    @Override
+    public synchronized void removeOperationalData(InstanceIdentifier<? extends DataObject> path) {
+        delegate.removeOperationalData(path);
+    }
+
+    @Override
+    public synchronized void removeConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+        delegate.removeConfigurationData(path);
+    }
+
+    @Override
+    public synchronized Set<InstanceIdentifier<? extends DataObject>> getRemovedConfigurationData() {
+        return delegate.getRemovedConfigurationData();
+    }
+
+    @Override
+    public synchronized Set<InstanceIdentifier<? extends DataObject>> getRemovedOperationalData() {
+        return delegate.getRemovedOperationalData();
+    }
+
+    @Override
+    public synchronized Map<InstanceIdentifier<? extends DataObject>, DataObject> getOriginalConfigurationData() {
+        return delegate.getOriginalConfigurationData();
+    }
+
+    @Override
+    public synchronized ListenerRegistration<DataTransactionListener> registerListener(DataTransactionListener listener) {
+        return delegate.registerListener(listener);
+    }
+
+    @Override
+    public synchronized Map<InstanceIdentifier<? extends DataObject>, DataObject> getOriginalOperationalData() {
+        return delegate.getOriginalOperationalData();
+    }
+
+    @Override
+    public synchronized DataModificationTransaction getDelegate() {
+        return delegate;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((delegate == null) ? 0 : delegate.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()){
+            return false;
+        }
+        SynchronizedTransaction other = (SynchronizedTransaction) obj;
+        if (delegate == null) {
+            if (other.delegate != null) {
+                return false;
+            }
+        } else if (!delegate.equals(other.delegate)) {
+            return false;
+        }
+        return true;
+    }
+}
+
index ea50e94..e5a74e4 100644 (file)
@@ -56,7 +56,7 @@
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.6.1</version>
+                       <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index e5cf8e6..244e350 100644 (file)
@@ -38,9 +38,23 @@ public class SingletonHolder {
         return NOTIFICATION_EXECUTOR;
     }
 
+    /**
+     * @deprecated This method is only used from configuration modules and thus callers of it
+     *             should use service injection to make the executor configurable.
+     */
+    @Deprecated
     public static synchronized final ListeningExecutorService getDefaultCommitExecutor() {
         if (COMMIT_EXECUTOR == null) {
-            COMMIT_EXECUTOR = createNamedExecutor("md-sal-binding-commit-%d");
+            ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-commit-%d").build();
+           /*
+            * FIXME: this used to be newCacheThreadPool(), but MD-SAL does not have transaction
+            *        ordering guarantees, which means that using a concurrent threadpool results
+            *        in application data being committed in random order, potentially resulting
+            *        in inconsistent data being present. Once proper primitives are introduced,
+            *        concurrency can be reintroduced.
+            */
+            ExecutorService executor = Executors.newSingleThreadExecutor(factory);
+            COMMIT_EXECUTOR = MoreExecutors.listeningDecorator(executor);
         }
 
         return COMMIT_EXECUTOR;
@@ -50,7 +64,5 @@ public class SingletonHolder {
         ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat(format).build();
         ExecutorService executor = Executors.newCachedThreadPool(factory);
         return MoreExecutors.listeningDecorator(executor);
-
     }
-
 }
index 52aa8d0..d997af5 100644 (file)
@@ -21,14 +21,20 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration
 import org.opendaylight.yangtools.concepts.Registration\r
 import org.opendaylight.yangtools.yang.binding.Notification\r
 import org.slf4j.LoggerFactory\r
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\rimport com.google.common.collect.Multimaps
-
-class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\rimport com.google.common.collect.Multimaps\r
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry\r
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener\r
 \r
+class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
+    \r
+    val ListenerRegistry<NotificationInterestListener> interestListeners = ListenerRegistry.create;\r
+    \r
     val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;\r
 \r
     @Property\r
     var ExecutorService executor;\r
+    \r
+    val logger = LoggerFactory.getLogger(NotificationBrokerImpl)\r
 \r
     new() {\r
         listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create())\r
@@ -101,14 +107,26 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab
         NotificationListener<T> listener) {\r
         val reg = new GenericNotificationRegistration<T>(notificationType, listener, this);\r
         listeners.put(notificationType, listener);\r
+        announceNotificationSubscription(notificationType);\r
         return reg;\r
     }\r
+    \r
+    def announceNotificationSubscription(Class<? extends Notification> notification) {\r
+        for (listener : interestListeners) {\r
+            try {\r
+                listener.instance.onNotificationSubscribtion(notification);\r
+            } catch (Exception e) {\r
+                logger.error("", e.message)\r
+            }\r
+        }\r
+    }\r
 \r
     override registerNotificationListener(\r
         org.opendaylight.yangtools.yang.binding.NotificationListener listener) {\r
         val invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener);\r
         for (notifyType : invoker.supportedNotifications) {\r
             listeners.put(notifyType, invoker.invocationProxy)\r
+            announceNotificationSubscription(notifyType)\r
         }\r
         val registration = new GeneratedListenerRegistration(listener, invoker,this);\r
         return registration as Registration<org.opendaylight.yangtools.yang.binding.NotificationListener>;\r
@@ -128,6 +146,14 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab
         //FIXME: implement properly.\r
     }\r
     \r
+    override registerInterestListener(NotificationInterestListener interestListener) {\r
+        val registration = interestListeners.register(interestListener);\r
+        \r
+        for(notification : listeners.keySet) {\r
+            interestListener.onNotificationSubscribtion(notification);\r
+        }\r
+        return registration\r
+    }\r
 }\r
 \r
 class GenericNotificationRegistration<T extends Notification> extends AbstractObjectRegistration<NotificationListener<T>> implements ListenerRegistration<NotificationListener<T>> {\r
index a21b3f1..978c79e 100644 (file)
@@ -80,12 +80,14 @@ public class BindingDomConnectorDeployer {
         connector.startDataForwarding();
     }
 
-    public static void startNotificationForwarding(BindingIndependentConnector connector, NotificationProviderService baService, NotificationPublishService domService) {
+    public static void startNotificationForwarding(BindingIndependentConnector connector, 
+            NotificationProviderService baService, NotificationPublishService domService) {
         if(connector.isNotificationForwarding()) {
             return;
         }
-
-        // FIXME
+        connector.setBindingNotificationService(baService);
+        connector.setDomNotificationService(domService);
+        connector.startNotificationForwarding();
     }
 
     //
index aaed12f..5630664 100644 (file)
@@ -17,6 +17,7 @@ import java.lang.reflect.Proxy;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -37,6 +38,8 @@ import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
@@ -55,6 +58,8 @@ import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
@@ -65,6 +70,7 @@ import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -93,7 +99,7 @@ public class BindingIndependentConnector implements //
 
     private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
 
-    @SuppressWarnings( "deprecation")
+    @SuppressWarnings("deprecation")
     private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
 
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
@@ -101,7 +107,6 @@ public class BindingIndependentConnector implements //
 
     private final static Method EQUALS_METHOD;
 
-
     private BindingIndependentMappingService mappingService;
 
     private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
@@ -146,10 +151,13 @@ public class BindingIndependentConnector implements //
 
     private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
 
+    private NotificationProviderService baNotifyService;
+
+    private NotificationPublishService domNotificationService;
 
     static {
         try {
-        EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
+            EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -311,7 +319,7 @@ public class BindingIndependentConnector implements //
                 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
                 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
             }
-            if(biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
+            if (biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
                 biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
             }
             rpcForwarding = true;
@@ -320,7 +328,11 @@ public class BindingIndependentConnector implements //
 
     public void startNotificationForwarding() {
         checkState(!notificationForwarding, "Connector is already forwarding notifications.");
-        notificationForwarding = true;
+        if (baNotifyService != null && domNotificationService != null) {
+            baNotifyService.registerInterestListener(new DomToBindingNotificationForwarder());
+
+            notificationForwarding = true;
+        }
     }
 
     protected void setMappingService(BindingIndependentMappingService mappingService) {
@@ -616,7 +628,7 @@ public class BindingIndependentConnector implements //
                 }
                 createDefaultDomForwarder();
             } catch (Exception e) {
-                LOG.error("Could not forward Rpcs of type {}", service.getName(),e);
+                LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
             }
             registrations = registrationsBuilder.build();
         }
@@ -635,13 +647,13 @@ public class BindingIndependentConnector implements //
 
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-            if(EQUALS_METHOD.equals(method)) {
+            if (EQUALS_METHOD.equals(method)) {
                 return false;
             }
             RpcInvocationStrategy strategy = strategiesByMethod.get(method);
             checkState(strategy != null);
             checkArgument(args.length <= 2);
-            if(args.length == 1) {
+            if (args.length == 1) {
                 checkArgument(args[0] instanceof DataObject);
                 return strategy.forwardToDomBroker((DataObject) args[0]);
             }
@@ -719,9 +731,10 @@ public class BindingIndependentConnector implements //
                     RpcInvocationStrategy strategy = null;
                     if (outputClass.isPresent()) {
                         if (inputClass.isPresent()) {
-                            strategy = new DefaultInvocationStrategy(rpc,targetMethod, outputClass.get(), inputClass.get());
+                            strategy = new DefaultInvocationStrategy(rpc, targetMethod, outputClass.get(), inputClass
+                                    .get());
                         } else {
-                            strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod);
+                            strategy = new NoInputNoOutputInvocationStrategy(rpc, targetMethod);
                         }
                     } else if(inputClass.isPresent()){
                         strategy = new NoOutputInvocationStrategy(rpc,targetMethod, inputClass.get());
@@ -740,7 +753,7 @@ public class BindingIndependentConnector implements //
         protected final Method targetMethod;
         protected final QName rpc;
 
-        public RpcInvocationStrategy(QName rpc,Method targetMethod) {
+        public RpcInvocationStrategy(QName rpc, Method targetMethod) {
             this.targetMethod = targetMethod;
             this.rpc = rpc;
         }
@@ -766,19 +779,25 @@ public class BindingIndependentConnector implements //
         @SuppressWarnings({ "rawtypes", "unchecked" })
         public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class<?> outputClass,
                 Class<? extends DataContainer> inputClass) {
-            super(rpc,targetMethod);
+            super(rpc, targetMethod);
             this.outputClass = new WeakReference(outputClass);
             this.inputClass = new WeakReference(inputClass);
         }
 
+        @SuppressWarnings("unchecked")
         @Override
         public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
             DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
-            Future<RpcResult<?>> result = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
-            if (result == null) {
+            Future<RpcResult<?>> futureResult = (Future<RpcResult<?>>) targetMethod.invoke(rpcService, bindingInput);
+            if (futureResult == null) {
                 return Rpcs.getRpcResult(false);
             }
-            RpcResult<?> bindingResult = result.get();
+            RpcResult<?> bindingResult = futureResult.get();
+            final Object resultObj = bindingResult.getResult();
+            if (resultObj instanceof DataObject) {
+                final CompositeNode output = mappingService.toDataDom((DataObject)resultObj);
+                return Rpcs.getRpcResult(true, output, Collections.<RpcError>emptySet());
+            }
             return Rpcs.getRpcResult(true);
         }
 
@@ -786,16 +805,16 @@ public class BindingIndependentConnector implements //
         public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
             if(biRouter != null) {
                 CompositeNode xml = mappingService.toDataDom(input);
-                CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
+                CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
                 RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
                 Object baResultValue = null;
-                if(result.getResult() != null) {
+                if (result.getResult() != null) {
                     baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
                 }
                 RpcResult<?> baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors());
-                return Futures.<RpcResult<?>>immediateFuture(baResult);
+                return Futures.<RpcResult<?>> immediateFuture(baResult);
             }
-            return Futures.<RpcResult<?>>immediateFuture(Rpcs.getRpcResult(false));
+            return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
         }
 
     }
@@ -803,7 +822,7 @@ public class BindingIndependentConnector implements //
     private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
 
         public NoInputNoOutputInvocationStrategy(QName rpc, Method targetMethod) {
-            super(rpc,targetMethod);
+            super(rpc, targetMethod);
         }
 
         public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
@@ -874,4 +893,54 @@ public class BindingIndependentConnector implements //
     public BindingIndependentMappingService getMappingService() {
         return mappingService;
     }
+
+    public void setBindingNotificationService(NotificationProviderService baService) {
+        this.baNotifyService = baService;
+
+    }
+
+    public void setDomNotificationService(NotificationPublishService domService) {
+        this.domNotificationService = domService;
+    }
+    
+    private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener {
+
+        private ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
+        private Set<QName> supportedNotifications = new HashSet<>();
+        
+        @Override
+        public Set<QName> getSupportedNotifications() {
+            return Collections.unmodifiableSet(supportedNotifications);
+        }
+
+        @Override
+        public void onNotification(CompositeNode notification) {
+            QName qname = notification.getNodeType();
+            WeakReference<Class<? extends Notification>> potential = notifications.get(qname);
+            if (potential != null) {
+                Class<? extends Notification> potentialClass = potential.get();
+                if (potentialClass != null) {
+                    final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass,
+                            notification);
+                    
+                    if (baNotification instanceof Notification) {
+                        baNotifyService.publish((Notification) baNotification);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onNotificationSubscribtion(Class<? extends Notification> notificationType) {
+            QName qname = BindingReflections.findQName(notificationType);
+            if (qname != null) {
+                WeakReference<Class<? extends Notification>> already = notifications.putIfAbsent(qname,
+                        new WeakReference<Class<? extends Notification>>(notificationType));
+                if (already == null) {
+                    domNotificationService.addNotificationListener(qname, this);
+                    supportedNotifications.add(qname);
+                }
+            }
+        }
+    }
 }
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMountPointForwarder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMountPointForwarder.java
deleted file mode 100644 (file)
index 7b94845..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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.sal.binding.impl.connect.dom;
-
-import java.util.concurrent.ConcurrentMap;
-
-import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance;
-import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService.MountProvisionListener;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-public class BindingIndependentMountPointForwarder {
-
-    private MountProvisionService domMountService;
-    private MountProviderService baMountService;
-    private BindingIndependentMappingService mappingService;
-
-    private final DomMountPointForwardingManager domForwardingManager = new DomMountPointForwardingManager();
-    private final BindingMountPointForwardingManager bindingForwardingManager = new BindingMountPointForwardingManager();
-
-    private ConcurrentMap<InstanceIdentifier<?>, BindingIndependentConnector> connectors;
-    private ConcurrentMap<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> forwarded;
-    private ListenerRegistration<MountProvisionListener> domListenerRegistration;
-    private ListenerRegistration<org.opendaylight.controller.sal.binding.api.mount.MountProviderService.MountProvisionListener> baListenerRegistration;
-
-    public MountProvisionService getDomMountService() {
-        return domMountService;
-    }
-
-    public void setDomMountService(MountProvisionService domMountService) {
-        this.domMountService = domMountService;
-    }
-
-    public void start() {
-        if(domMountService != null && baMountService != null) {
-            domListenerRegistration = domMountService.registerProvisionListener(domForwardingManager);
-            baListenerRegistration = baMountService.registerProvisionListener(bindingForwardingManager);
-        }
-    }
-
-    private void tryToDeployConnector(InstanceIdentifier<?> baPath,
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath) {
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier previous = forwarded.putIfAbsent(baPath, biPath);
-        if(previous != null) {
-            return;
-        }
-        MountProviderInstance baMountPoint = baMountService.getMountPoint(baPath);
-        MountProvisionInstance domMountPoint = domMountService.getMountPoint(biPath);
-        BindingIndependentConnector connector = createForwarder(baPath, baMountPoint, domMountPoint);
-        connectors.put(baPath, connector);
-        connector.startDataForwarding();
-        connector.startRpcForwarding();
-        connector.startNotificationForwarding();
-    }
-
-    private BindingIndependentConnector createForwarder(InstanceIdentifier<?> path, MountProviderInstance baMountPoint,
-            MountProvisionInstance domMountPoint) {
-        BindingIndependentConnector connector = new BindingIndependentConnector();
-
-        connector.setBindingDataService(baMountPoint);
-        connector.setBindingRpcRegistry(baMountPoint);
-        //connector.setBindingNotificationBroker(baMountPoint);
-
-        connector.setDomDataService(domMountPoint);
-        connector.setDomRpcRegistry(domMountPoint);
-        //connector.setDomNotificationBroker(domMountPoint);
-        return connector;
-    }
-
-    public synchronized void tryToDeployDomForwarder(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath) {
-        InstanceIdentifier<?> baPath;
-        try {
-            baPath = mappingService.fromDataDom(domPath);
-            BindingIndependentConnector potentialConnector = connectors.get(baPath);
-            if(potentialConnector != null) {
-                return;
-            }
-            tryToDeployConnector(baPath,domPath);
-        } catch (DeserializationException e) {
-
-        }
-    }
-
-    public synchronized void tryToDeployBindingForwarder(InstanceIdentifier<?> baPath) {
-        BindingIndependentConnector potentialConnector =connectors.get(baPath);
-        if(potentialConnector != null) {
-            return;
-        }
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(baPath);
-        tryToDeployConnector(baPath, domPath);
-    }
-
-    public synchronized void undeployBindingForwarder(InstanceIdentifier<?> baPath) {
-        // FIXME: Implement closeMountPoint
-    }
-
-    public synchronized void undeployDomForwarder(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath) {
-        // FIXME: Implement closeMountPoint
-    }
-
-    private class DomMountPointForwardingManager implements MountProvisionListener {
-
-        @Override
-        public void onMountPointCreated(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path) {
-            tryToDeployDomForwarder(path);
-        }
-
-        @Override
-        public void onMountPointRemoved(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path) {
-            undeployDomForwarder(path);
-        }
-    }
-
-    private class BindingMountPointForwardingManager implements
-            org.opendaylight.controller.sal.binding.api.mount.MountProviderService.MountProvisionListener {
-
-        @Override
-        public void onMountPointCreated(InstanceIdentifier<?> path) {
-            tryToDeployBindingForwarder(path);
-        }
-
-        @Override
-        public void onMountPointRemoved(InstanceIdentifier<?> path) {
-            undeployBindingForwarder(path);
-        }
-    }
-}
index c90f6fd..8c74008 100644 (file)
@@ -108,7 +108,7 @@ public class DomForwardedBindingBrokerImpl extends RootBindingAwareBroker implem
         BindingDomConnectorDeployer.startRpcForwarding(mountConnector, baMountPoint, domMountPoint);
         BindingDomConnectorDeployer.startNotificationForwarding(mountConnector, baMountPoint, domMountPoint);
         // connector.setDomNotificationBroker(domMountPoint);
-        return connector;
+        return mountConnector;
     }
 
     public synchronized void tryToDeployDomForwarder(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath) {
index aec9fe4..d87e272 100644 (file)
@@ -69,7 +69,7 @@
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.6.1</version>
+                       <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index 2a8ebe8..c7d6640 100644 (file)
@@ -99,4 +99,10 @@ public abstract class AbstractBindingSalProviderInstance<D extends DataProviderS
             L listener) {
         return getRpcRegistryChecked().registerRouteChangeListener(listener);
     }
+    
+    @Override
+    public ListenerRegistration<NotificationInterestListener> registerInterestListener(
+            NotificationInterestListener interestListener) {
+        return getNotificationBrokerChecked().registerInterestListener(interestListener);
+    }
 }
index 437051e..5dd08d0 100644 (file)
@@ -26,7 +26,6 @@
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>concepts</artifactId>
-            <version>0.6.1</version>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
index d74b26d..29ba192 100644 (file)
@@ -37,8 +37,46 @@ public interface DataModification<P/* extends Path<P> */, D> extends DataChange<
     @Deprecated
     void putRuntimeData(P path, D data);
 
+    /**
+     * Store a piece of data at specified path. This acts as a merge operation,
+     * which is to say that any pre-existing data which is not explicitly
+     * overwritten will be preserved. This means that if you store a container,
+     * its child lists will be merged. Performing the following put operations:
+     *
+     * 1) container { list [ a ] }
+     * 2) container { list [ b ] }
+     *
+     * will result in the following data being present:
+     *
+     * container { list [ a, b ] }
+     *
+     * This also means that storing the container will preserve any augmentations
+     * which have been attached to it.
+     *
+     * If you require an explicit replace operation, perform
+     * {@link removeOperationalData} first.
+     */
     void putOperationalData(P path, D data);
 
+    /**
+     * Store a piece of data at specified path. This acts as a merge operation,
+     * which is to say that any pre-existing data which is not explicitly
+     * overwritten will be preserved. This means that if you store a container,
+     * its child lists will be merged. Performing the following put operations:
+     *
+     * 1) container { list [ a ] }
+     * 2) container { list [ b ] }
+     *
+     * will result in the following data being present:
+     *
+     * container { list [ a, b ] }
+     *
+     * This also means that storing the container will preserve any augmentations
+     * which have been attached to it.
+     *
+     * If you require an explicit replace operation, perform
+     * {@link removeConfigurationData} first.
+     */
     void putConfigurationData(P path, D data);
 
     /**
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChain.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChain.java
new file mode 100644 (file)
index 0000000..ff3aa2e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.common.api.data;
+
+/**
+ * A chain of transactions. Transactions in a chain need to be committed in sequence and each
+ * transaction should see the effects of previous transactions as if they happened. A chain
+ * makes no guarantees of atomicity, in fact transactions are committed as soon as possible.
+ */
+public interface TransactionChain<P/* extends Path<P> */, D> extends AutoCloseable {
+    /**
+     * Create a new transaction which will continue the chain. The previous transaction
+     * has to be either COMMITTED or CANCELLED.
+     *
+     * @return New transaction in the chain.
+     * @throws IllegalStateException if the previous transaction was not COMMITTED or CANCELLED.
+     * @throws TransactionChainClosedException if the chain has been closed.
+     */
+    DataModification<P, D> newTransaction();
+
+    @Override
+    void close();
+}
+
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainClosedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainClosedException.java
new file mode 100644 (file)
index 0000000..5e1b35d
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.common.api.data;
+
+/**
+ * Exception thrown when an attempt is made to open a new transaction in a closed
+ * chain.
+ */
+public final class TransactionChainClosedException extends IllegalStateException {
+    private static final long serialVersionUID = 1L;
+
+    public TransactionChainClosedException(final String message) {
+        super(message);
+    }
+
+    public TransactionChainClosedException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainFactory.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainFactory.java
new file mode 100644 (file)
index 0000000..4e7e12e
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013 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.common.api.data;
+
+/**
+ * Interface for creating transaction chains.
+ */
+public interface TransactionChainFactory<P/* extends Path<P> */, D> {
+    /**
+     * Create a new transaction chain. The chain will be initialized to read
+     * from its backing datastore, with no outstanding transaction. Listener
+     * will be registered to handle chain-level events.
+     *
+     * @param listener Transaction chain event listener
+     * @return A new transaction chain.
+     */
+    TransactionChain<P, D> createTransactionChain(TransactionChainListener listener);
+}
+
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainListener.java
new file mode 100644 (file)
index 0000000..4dac6f5
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.common.api.data;
+
+import java.util.EventListener;
+
+/**
+ * Listener for transaction chain events.
+ */
+public interface TransactionChainListener extends EventListener {
+    /**
+     * Invoked if when a transaction in the chain fails. All other transactions are automatically cancelled by the time
+     * this notification is invoked. Implementations should invoke chain.close() to close the chain.
+     *
+     * @param chain Transaction chain which failed
+     * @param transaction Transaction which caused the chain to fail
+     * @param cause The cause of transaction failure
+     */
+    void onTransactionChainFailed(TransactionChain<?, ?> chain, DataModification<?, ?> transaction, Throwable cause);
+
+    /**
+     * Invoked when a transaction chain is completed. A transaction chain is considered completed when it has been
+     * closed and all its instructions have completed successfully.
+     *
+     * @param chain Transaction chain which completed
+     */
+    void onTransactionChainSuccessful(TransactionChain<?, ?> chain);
+}
+
index 9a61e98..4b6a018 100644 (file)
@@ -75,7 +75,6 @@ public abstract class AbstractDataModification<P extends Path<P>, D> implements
         }
 
         configurationUpdate.put(path, mergeConfigurationData(path,original, data));
-        configurationRemove.remove(path);
     }
 
     @Override
@@ -86,7 +85,6 @@ public abstract class AbstractDataModification<P extends Path<P>, D> implements
             operationalCreated.put(path, data);
         }
         operationalUpdate.put(path, mergeOperationalData(path,original,data));
-        operationalRemove.remove(path);
     }
 
     @Override
index 927975c..2c3b018 100644 (file)
@@ -45,6 +45,8 @@ import org.slf4j.LoggerFactory
 \r
 import static com.google.common.base.Preconditions.*\rimport org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent
 import com.google.common.collect.Multimaps
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
 
 abstract class AbstractDataBroker<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements DataModificationTransactionFactory<P, D>, //\r
 DataReader<P, D>, //\r
@@ -70,16 +72,20 @@ DataProvisionService<P, D> {
 \r
     Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
     Multimap<P, DataCommitHandlerRegistrationImpl<P, D>> commitHandlers = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
+    
+    private val Lock registrationLock = new ReentrantLock;
     \r
     val ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P,D>>> commitHandlerRegistrationListeners = new ListenerRegistry();\r
     public new() {\r
     }\r
 \r
     protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedCommitHandlers(\r
-        HashSet<P> paths) {\r
-        return FluentIterable.from(commitHandlers.asMap.entrySet).filter[key.isAffectedBy(paths)] //\r
-        .transformAndConcat[value] //\r
-        .transform[instance].toList()\r
+        HashSet<P> paths) {
+        return withLock(registrationLock) [|\r
+            return FluentIterable.from(commitHandlers.asMap.entrySet).filter[key.isAffectedBy(paths)] //\r
+                .transformAndConcat[value] //\r
+                .transform[instance].toList()
+        ]\r
     }\r
 \r
     override final readConfigurationData(P path) {\r
@@ -88,43 +94,56 @@ DataProvisionService<P, D> {
 \r
     override final readOperationalData(P path) {\r
         return dataReadRouter.readOperationalData(path);\r
-    }\r
-\r
-    override final registerCommitHandler(P path, DataCommitHandler<P, D> commitHandler) {\r
-        val registration = new DataCommitHandlerRegistrationImpl(path, commitHandler, this);\r
-        commitHandlers.put(path, registration)\r
-        LOG.trace("Registering Commit Handler {} for path: {}",commitHandler,path);\r
-        for(listener : commitHandlerRegistrationListeners) {\r
-            try {\r
-                listener.instance.onRegister(registration);\r
-            } catch (Exception e) {\r
-                LOG.error("Unexpected exception in listener {} during invoking onRegister",listener.instance,e);\r
-            }\r
-        }\r
-        return registration;\r
+    }
+    
+    private static def <T> withLock(Lock lock,Callable<T> method) {
+        lock.lock
+        try {
+            return method.call
+        } finally {
+            lock.unlock
+        }
+    } \r
+\r
+    override final registerCommitHandler(P path, DataCommitHandler<P, D> commitHandler) {
+        return withLock(registrationLock) [|\r
+            val registration = new DataCommitHandlerRegistrationImpl(path, commitHandler, this);\r
+            commitHandlers.put(path, registration)\r
+            LOG.trace("Registering Commit Handler {} for path: {}",commitHandler,path);\r
+            for(listener : commitHandlerRegistrationListeners) {\r
+                try {\r
+                    listener.instance.onRegister(registration);\r
+                } catch (Exception e) {\r
+                    LOG.error("Unexpected exception in listener {} during invoking onRegister",listener.instance,e);\r
+                }\r
+            }
+            return registration;
+        ]\r
     }\r
 \r
     override final def registerDataChangeListener(P path, DCL listener) {\r
-        val reg = new DataChangeListenerRegistration(path, listener, this);\r
-        listeners.put(path, reg);\r
-        val initialConfig = dataReadRouter.readConfigurationData(path);\r
-        val initialOperational = dataReadRouter.readOperationalData(path);\r
-        val event = createInitialListenerEvent(path,initialConfig,initialOperational);\r
-        listener.onDataChanged(event);\r
-        return reg;\r
+        return withLock(registrationLock) [|
+            val reg = new DataChangeListenerRegistration(path, listener, this);\r
+            listeners.put(path, reg);\r
+            val initialConfig = dataReadRouter.readConfigurationData(path);\r
+            val initialOperational = dataReadRouter.readOperationalData(path);\r
+            val event = createInitialListenerEvent(path,initialConfig,initialOperational);\r
+            listener.onDataChanged(event);\r
+            return reg;
+        ]\r
     }\r
 \r
     final def registerDataReader(P path, DataReader<P, D> reader) {\r
-\r
-        val confReg = dataReadRouter.registerConfigurationReader(path, reader);\r
-        val dataReg = dataReadRouter.registerOperationalReader(path, reader);\r
-\r
-        return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg));\r
+        return withLock(registrationLock) [|\r
+            val confReg = dataReadRouter.registerConfigurationReader(path, reader);\r
+            val dataReg = dataReadRouter.registerOperationalReader(path, reader);\r
+    \r
+            return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg));
+        ]\r
     }\r
     \r
     override registerCommitHandlerListener(RegistrationListener<DataCommitHandlerRegistration<P, D>> commitHandlerListener) {\r
         val ret = commitHandlerRegistrationListeners.register(commitHandlerListener);\r
-        \r
         return ret;\r
     }\r
     \r
@@ -133,21 +152,25 @@ DataProvisionService<P, D> {
         \r
     }\r
 \r
-    protected final def removeListener(DataChangeListenerRegistration<P, D, DCL> registration) {\r
-        listeners.remove(registration.path, registration);\r
+    protected final def removeListener(DataChangeListenerRegistration<P, D, DCL> registration) {
+        return withLock(registrationLock) [|\r
+            listeners.remove(registration.path, registration);
+        ]\r
     }\r
 \r
     protected final def removeCommitHandler(DataCommitHandlerRegistrationImpl<P, D> registration) {\r
-        commitHandlers.remove(registration.path, registration);\r
-        \r
-         LOG.trace("Removing Commit Handler {} for path: {}",registration.instance,registration.path);\r
-        for(listener : commitHandlerRegistrationListeners) {\r
-            try {\r
-                listener.instance.onUnregister(registration);\r
-            } catch (Exception e) {\r
-                LOG.error("Unexpected exception in listener {} during invoking onUnregister",listener.instance,e);\r
-            }\r
-        }\r
+        return withLock(registrationLock) [|
+            commitHandlers.remove(registration.path, registration);\r
+             LOG.trace("Removing Commit Handler {} for path: {}",registration.instance,registration.path);\r
+            for(listener : commitHandlerRegistrationListeners) {\r
+                try {\r
+                    listener.instance.onUnregister(registration);\r
+                } catch (Exception e) {\r
+                    LOG.error("Unexpected exception in listener {} during invoking onUnregister",listener.instance,e);\r
+                }\r
+            }
+            return null;
+        ]\r
     }\r
 \r
     protected final def getActiveCommitHandlers() {\r
@@ -155,12 +178,14 @@ DataProvisionService<P, D> {
     }\r
 \r
     protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedListenersWithInitialState(\r
-        HashSet<P> paths) {\r
-        return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [\r
-            val operationalState = readOperationalData(key)\r
-            val configurationState = readConfigurationData(key)\r
-            return new ListenerStateCapture(key, value, operationalState, configurationState)\r
-        ].toList()\r
+        HashSet<P> paths) {
+        return withLock(registrationLock) [|\r
+            return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [\r
+                val operationalState = readOperationalData(key)\r
+                val configurationState = readConfigurationData(key)\r
+                return new ListenerStateCapture(key, value, operationalState, configurationState)\r
+            ].toList()
+        ]\r
     }\r
 \r
     protected def boolean isAffectedBy(P key, Set<P> paths) {\r
@@ -267,12 +292,13 @@ package class TwoPhaseCommit<P extends Path<P>, D, DCL extends DataChangeListene
         affectedPaths.addAll(transaction.createdOperationalData.keySet);\r
         affectedPaths.addAll(transaction.updatedOperationalData.keySet);\r
         affectedPaths.addAll(transaction.removedOperationalData);\r
-\r
+
         val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths);\r
 \r
         val transactionId = transaction.identifier;\r
 \r
         log.trace("Transaction: {} Started.",transactionId);\r
+        log.trace("Transaction: {} Affected Subtrees:",transactionId,affectedPaths);
         // requesting commits\r
         val Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths);\r
         val List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList();\r
@@ -283,6 +309,7 @@ package class TwoPhaseCommit<P extends Path<P>, D, DCL extends DataChangeListene
         } catch (Exception e) {\r
             log.error("Transaction: {} Request Commit failed", transactionId,e);\r
             dataBroker.failedTransactionsCount.andIncrement\r
+            transaction.changeStatus(TransactionStatus.FAILED)
             return rollback(handlerTransactions, e);\r
         }\r
         val List<RpcResult<Void>> results = new ArrayList();\r
@@ -293,11 +320,13 @@ package class TwoPhaseCommit<P extends Path<P>, D, DCL extends DataChangeListene
             listeners.publishDataChangeEvent();\r
         } catch (Exception e) {\r
             log.error("Transaction: {} Finish Commit failed",transactionId, e);\r
-            dataBroker.failedTransactionsCount.andIncrement\r
+            dataBroker.failedTransactionsCount.andIncrement
+            transaction.changeStatus(TransactionStatus.FAILED)\r
             return rollback(handlerTransactions, e);\r
         }\r
         log.trace("Transaction: {} Finished successfully.",transactionId);\r
-        dataBroker.finishedTransactionsCount.andIncrement;\r
+        dataBroker.finishedTransactionsCount.andIncrement;
+        transaction.changeStatus(TransactionStatus.COMMITED)\r
         return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet());\r
 \r
     }\r
index 2ec66b5..3a9b00d 100644 (file)
@@ -21,7 +21,6 @@
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>concepts</artifactId>
-      <version>0.6.1</version>
     </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
index 76d80d1..d7b0296 100644 (file)
@@ -59,7 +59,7 @@
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.6.1</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index 5b883d7..8b193e0 100644 (file)
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.6.1</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index 098cd92..023f906 100644 (file)
@@ -44,7 +44,6 @@ class MountPointManagerImpl implements MountProvisionService {
     def registerMountPoint(MountPointImpl impl) {
         //dataBroker?.registerConfigurationReader(impl.mountPath,impl.readWrapper);
         //dataBroker?.registerOperationalReader(impl.mountPath,impl.readWrapper);
-        
     }
     
     override registerProvisionListener(MountProvisionListener listener) {
index 3723671..cc44613 100644 (file)
@@ -85,7 +85,7 @@ class DataReaderRouter extends AbstractDataReadRouter<InstanceIdentifier, Compos
             val simpleNode = node.getSimpleNodesByName(keyValue.key);
             if(simpleNode !== null && !simpleNode.empty) {
                 checkState(simpleNode.size <= 1,"Only one simple node for key $s is allowed in node $s",keyValue.key,node);
-                checkState(simpleNode.get(0).value == keyValue.value,"Key node must equals to instance identifier value");
+                checkState(simpleNode.get(0).value == keyValue.value,"Key node must equal to instance identifier value in node $s",node);
                 ret.put(keyValue.key,simpleNode.get(0));
             }
             val compositeNode = node.getCompositesByName(keyValue.key);
index 5fc2c1d..9600881 100644 (file)
@@ -64,15 +64,15 @@ class HashMapDataStore implements DataStore, AutoCloseable {
 
     def RpcResult<Void> finish(HashMapDataStoreTransaction transaction) {
         val modification = transaction.modification;
-        configuration.putAll(modification.updatedConfigurationData);
-        operational.putAll(modification.updatedOperationalData);
-
         for (removal : modification.removedConfigurationData) {
             remove(configuration,removal);
         }
         for (removal : modification.removedOperationalData) {
             remove(operational,removal);
         }
+        configuration.putAll(modification.updatedConfigurationData);
+        operational.putAll(modification.updatedOperationalData);
+
         return Rpcs.getRpcResult(true, null, Collections.emptySet);
     }
     
index 763407f..0b184fc 100644 (file)
@@ -40,14 +40,15 @@ public class NotificationRouterImpl implements NotificationRouter {
     private static Logger log = LoggerFactory.getLogger(NotificationRouterImpl.class);
 
     private Multimap<QName, Registration<NotificationListener>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.<QName, Registration<NotificationListener>>create());
-
+//    private Registration<NotificationListener> defaultListener;
+    
     private void sendNotification(CompositeNode notification) {
-        QName type = notification.getNodeType();
-        Collection<Registration<NotificationListener>> toNotify = listeners.get(type);
+        final QName type = notification.getNodeType();
+        final Collection<Registration<NotificationListener>> toNotify = listeners.get(type);
         log.trace("Publishing notification " + type);
 
-        if (toNotify == null) {
-            // No listeners were registered - returns.
+        if ((toNotify == null) || toNotify.isEmpty()) {
+            log.debug("No listener registered for handling of notification {}", type);
             return;
         }
 
@@ -59,17 +60,17 @@ public class NotificationRouterImpl implements NotificationRouter {
                 log.error("Uncaught exception in NotificationListener", e);
             }
         }
-
     }
 
     @Override
     public void publish(CompositeNode notification) {
         sendNotification(notification);
     }
-
+    
     @Override
     public Registration<NotificationListener> addNotificationListener(QName notification, NotificationListener listener) {
         ListenerRegistration ret = new ListenerRegistration(notification, listener);
+        listeners.put(notification, ret);
         return ret;
     }
 
index a9ec2c7..1e89281 100644 (file)
@@ -70,7 +70,7 @@ class YangDataOperations {
         
         if(node.keyDefinition === null || node.keyDefinition.empty) {
             return modified;
-        } 
+        }
         val originalMap = (original as List).toIndexMap(node.keyDefinition);
         val modifiedMap = (modified as List).toIndexMap(node.keyDefinition);
         
@@ -80,7 +80,8 @@ class YangDataOperations {
             if(originalEntry != null) {
                 originalMap.remove(entry.key);
                 mergedNodes.add(merge(node,originalEntry,entry.value,configurational));
-                
+            } else {
+                mergedNodes.add(entry.value);
             }
         }
         mergedNodes.addAll(originalMap.values);
index 7f15062..7f6918f 100644 (file)
@@ -31,7 +31,6 @@ import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UsesNode;
-import org.opendaylight.yangtools.yang.model.api.YangNode;
 
 import static com.google.common.base.Preconditions.*;
 
@@ -127,11 +126,6 @@ public class YangSchemaUtils {
         public NetconfDataRootNode(SchemaContext schema) {
             // TODO Auto-generated constructor stub
         }
-
-        public YangNode getParent() {
-            // TODO Auto-generated method stub
-            return null;
-        }
     
         @Override
         public Set<TypeDefinition<?>> getTypeDefinitions() {
index f90c966..597b02e 100644 (file)
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.6.1</version>
+                       <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index cedc0d4..a04baaa 100644 (file)
@@ -7,18 +7,9 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.connector.netconf;
 
+import com.google.common.net.InetAddresses;
 import io.netty.channel.EventLoopGroup;
 import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.io.File;
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import javax.net.ssl.SSLContext;
-
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
@@ -31,17 +22,25 @@ import org.opendaylight.yangtools.yang.model.util.repo.FilesystemSchemaCachingPr
 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProviders;
 import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import static com.google.common.base.Preconditions.*;
+import java.io.File;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
-import com.google.common.base.Optional;
-import com.google.common.net.InetAddresses;
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
 
 /**
 *
 */
 public final class NetconfConnectorModule extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModule
 {
+    private static final Logger logger = LoggerFactory.getLogger(NetconfConnectorModule.class);
 
     private static ExecutorService GLOBAL_PROCESSING_EXECUTOR = null;
     private static AbstractCachingSchemaSourceProvider<String, InputStream> GLOBAL_NETCONF_SOURCE_PROVIDER = null;
@@ -56,14 +55,20 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
     }
 
     @Override
-    public void validate(){
-        super.validate();
-        checkState(getAddress() != null,"Address must be set.");
+    protected void customValidation() {
+        checkNotNull(getAddress(), addressJmxAttribute);
         //checkState(getAddress().getIpv4Address() != null || getAddress().getIpv6Address() != null,"Address must be set.");
-        checkState(getPort() != null,"Port must be set.");
-        checkState(getDomRegistry() != null,"Dom Registry must be provided.");
-    }
+        checkNotNull(getPort(), portJmxAttribute);
+        checkNotNull(getDomRegistry(), portJmxAttribute);
+        checkNotNull(getDomRegistry(), domRegistryJmxAttribute);
+
+        checkNotNull(getConnectionTimeoutMillis(), connectionTimeoutMillisJmxAttribute);
+        checkCondition(getConnectionTimeoutMillis() > 0, "must be > 0", connectionTimeoutMillisJmxAttribute);
 
+        checkNotNull(getBetweenAttemptsTimeoutMillis(), betweenAttemptsTimeoutMillisJmxAttribute);
+        checkCondition(getBetweenAttemptsTimeoutMillis() > 0, "must be > 0", betweenAttemptsTimeoutMillisJmxAttribute);
+
+    }
 
     @Override
     public java.lang.AutoCloseable createInstance() {
@@ -71,10 +76,15 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         getDomRegistryDependency();
         NetconfDevice device = new NetconfDevice(getIdentifier().getInstanceName());
         String addressValue = getAddress();
-        
-        
-        int attemptMsTimeout = 60*1000;
-        int connectionAttempts = 5;
+
+        Long connectionAttempts;
+        if (getMaxConnectionAttempts() != null && getMaxConnectionAttempts() > 0) {
+            connectionAttempts = getMaxConnectionAttempts();
+        } else {
+            logger.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
+            connectionAttempts = null;
+        }
+        long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
         /*
          * Uncomment after Switch to IP Address
         if(getAddress().getIpv4Address() != null) {
@@ -83,8 +93,12 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
             addressValue = getAddress().getIpv6Address().getValue();
         }
         */
-        ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
-                Long.valueOf(connectionAttempts), null);
+        double sleepFactor = 1.0;
+        int minSleep = 1000;
+        Long maxSleep = null;
+        Long deadline = null;
+        ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(),
+                minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
         
         device.setReconnectStrategy(strategy);
         
@@ -96,7 +110,7 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         
         device.setSocketAddress(socketAddress);
         device.setEventExecutor(getEventExecutorDependency());
-        device.setDispatcher(createDispatcher());
+        device.setDispatcher(createDispatcher(clientConnectionTimeoutMillis));
         device.setSchemaSourceProvider(getGlobalNetconfSchemaProvider(bundleContext));
         
         getDomRegistryDependency().registerProvider(device, bundleContext);
@@ -124,14 +138,14 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         return GLOBAL_NETCONF_SOURCE_PROVIDER;
     }
 
-    private NetconfClientDispatcher createDispatcher() {
+    private NetconfClientDispatcher createDispatcher(long clientConnectionTimeoutMillis) {
         EventLoopGroup bossGroup = getBossThreadGroupDependency();
         EventLoopGroup workerGroup = getWorkerThreadGroupDependency();
         if(getTcpOnly()) {
-            return new NetconfClientDispatcher( bossGroup, workerGroup);
+            return new NetconfClientDispatcher( bossGroup, workerGroup, clientConnectionTimeoutMillis);
         } else {
             AuthenticationHandler authHandler = new LoginPassword(getUsername(),getPassword());
-            return new NetconfSshClientDispatcher(authHandler , bossGroup, workerGroup);
+            return new NetconfSshClientDispatcher(authHandler , bossGroup, workerGroup, clientConnectionTimeoutMillis);
         }
     }
 
index 87cbf13..69fe4aa 100644 (file)
@@ -78,17 +78,11 @@ class NetconfDeviceListener extends NetconfClientSessionListener {
      */
     public void onNotification(final NetconfClientSession session, final NetconfMessage message) {
         this.device.logger.debug("Received NETCONF notification.", message);
-        CompositeNode _notificationBody = null;
-        CompositeNode _compositeNode = null;
+        CompositeNode domNotification = null;
         if (message != null) {
-            _compositeNode = NetconfMapping.toCompositeNode(message,device.getSchemaContext());
+            domNotification = NetconfMapping.toNotificationNode(message, device.getSchemaContext());
         }
-        if (_compositeNode != null) {
-            _notificationBody = NetconfDeviceListener.getNotificationBody(_compositeNode);
-        }
-        final CompositeNode domNotification = _notificationBody;
-        boolean _notEquals = (!Objects.equal(domNotification, null));
-        if (_notEquals) {
+        if (domNotification != null) {
             MountProvisionInstance _mountInstance = null;
             if (this.device != null) {
                 _mountInstance = this.device.getMountInstance();
index 965df60..76a5506 100644 (file)
@@ -33,6 +33,8 @@ import com.google.common.base.Preconditions
 import com.google.common.base.Optional
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+import java.util.Set
 
 class NetconfMapping {
 
@@ -103,7 +105,19 @@ class NetconfMapping {
     }
 
     static def CompositeNode toCompositeNode(NetconfMessage message,Optional<SchemaContext> ctx) {
-        return null//message.toRpcResult().result;
+        //TODO: implement general normalization to normalize incoming Netconf Message 
+        // for Schema Context counterpart
+        return null
+    }
+    
+    static def CompositeNode toNotificationNode(NetconfMessage message,Optional<SchemaContext> ctx) {
+        if (ctx.present) {
+            val schemaContext = ctx.get
+            val notifications = schemaContext.notifications
+            val document = message.document
+            return XmlDocumentUtils.notificationToDomNodes(document, Optional.<Set<NotificationDefinition>>fromNullable(notifications))
+        }
+        return null
     }
 
     static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional<SchemaContext> ctx) {
@@ -134,11 +148,11 @@ class NetconfMapping {
             if(isDataRetrievalReply(rpc)) {
                 
                 val xmlData = message.document.dataSubtree
-                val dataNodes = XmlDocumentUtils.toDomNodes(xmlData,Optional.of(context.get.dataDefinitions))
+                val dataNodes = XmlDocumentUtils.toDomNodes(xmlData, Optional.of(context.get.dataDefinitions))
                 
                 val it = ImmutableCompositeNode.builder()
                 setQName(NETCONF_RPC_REPLY_QNAME)
-                add(ImmutableCompositeNode.create(NETCONF_DATA_QNAME,dataNodes));
+                add(ImmutableCompositeNode.create(NETCONF_DATA_QNAME, dataNodes));
                 
                 rawRpc = it.toInstance;
                 //sys(xmlData)
index 2331516..b28e72e 100644 (file)
@@ -88,6 +88,25 @@ module odl-sal-netconf-connector-cfg {
                     }
                 }
             }
+
+            leaf connection-timeout-millis {
+                description "Specifies timeout in milliseconds after which connection must be established.";
+                type uint32;
+                default 5000;
+            }
+
+            leaf max-connection-attempts {
+                description "Maximum number of connection retries. Non positive value or null is interpreted as infinity.";
+                type uint32;
+                default 0; // retry forever
+            }
+
+
+            leaf between-attempts-timeout-millis {
+                description "Timeout in milliseconds to wait between connection attempts.";
+                type uint16;
+                default 10000;
+            }
         }
     }
 }
\ No newline at end of file
index 619b42b..ae31c23 100644 (file)
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.6.1</version>
+                       <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/Draft01.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/Draft01.java
deleted file mode 100644 (file)
index 557adb6..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2013 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.sal.rest.api;
-
-public class Draft01 {
-    public static class MediaTypes {
-        public static final String API = "application/vnd.yang.api";
-        public static final String DATASTORE = "application/vnd.yang.datastore";
-        public static final String DATA = "application/vnd.yang.data";
-        public static final String EVENT = "application/vnd.yang.event";
-        public static final String OPERATION = "application/vnd.yang.operation";
-        public static final String PATCH = "application/vnd.yang.patch";
-    }
-}
index 60a8f28..848f2c4 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.rest.api;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -23,33 +24,28 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 /**
  *   The URI hierarchy for the RESTCONF resources consists of an entry
- *   point container, 3 top-level resources, and 1 field.  Refer to
- *  Section 5 for details on each URI.
- *    <ul>
+ *   point container, 4 top-level resources, and 1 field.
+ *   <ul>
  *    <li><b>/restconf</b> - {@link #getRoot()}
- *     <ul><li><b>/config</b> 
- *         <li><b>/operational</b> - {@link #readAllData()} - Added in Draft02
- *         <li><b>/datastore</b> - {@link #readAllData()}
- *         <ul>
- *            <li>/(top-level-data-nodes) (config=true or false)
- *         </ul>
- *         <li>/modules
- *          <ul><li>/module
- *              <li>/name
- *              <li>/revision
- *              <li>/namespace
- *              <li>/feature
- *             <li>/deviation
- *          </ul>
- *          <li>/operations
- *          <ul>
- *             <li>/(custom protocol operations)
- *          </ul>
- *         <li>/version (field)
+ *     <ul>
+ *      <li><b>/config</b> - {@link #readConfigurationData(String)} 
+ *                              {@link #updateConfigurationData(String, CompositeNode)}
+ *                              {@link #createConfigurationData(CompositeNode)}
+ *                              {@link #createConfigurationData(String, CompositeNode)}
+ *                              {@link #deleteConfigurationData(String)}
+ *      <li><b>/operational</b> - {@link #readOperationalData(String)} 
+ *      <li>/modules - {@link #getModules()}
+ *       <ul>
+ *        <li>/module
+ *       </ul>
+ *      <li><b>/operations</b> - {@link #invokeRpc(String, CompositeNode)}
+ *                               {@link #invokeRpc(String, CompositeNode)}
+ *      <li>/version (field)
  *     </ul>
+ *   </ul>
  */
 @Path("/")
-public interface RestconfService extends RestconfServiceLegacy {
+public interface RestconfService {
 
     public static final String XML = "+xml";
     public static final String JSON = "+json";
@@ -59,26 +55,25 @@ public interface RestconfService extends RestconfServiceLegacy {
 
     @GET
     @Path("/modules")
-    @Produces({Draft01.MediaTypes.API+JSON,Draft01.MediaTypes.API+XML,
-               Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML})
+    @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML})
     public StructuredData getModules();
 
     @POST
     @Path("/operations/{identifier}")
-    @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML,
-               Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, 
+    @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
+               Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    @Consumes({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML,
-               Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, 
+    @Consumes({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
+               Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
     public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
     
     @POST
     @Path("/operations/{identifier}")
-    @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML,
-               Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, 
+    @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
+               Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public StructuredData invokeRpc(@PathParam("identifier") String identifier);
+    public StructuredData invokeRpc(@PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
     
     @GET
     @Path("/config/{identifier:.+}")
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfServiceLegacy.java
deleted file mode 100644 (file)
index 7d6cbfe..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.sal.rest.api;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.opendaylight.controller.sal.restconf.impl.StructuredData;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-
-public interface RestconfServiceLegacy {
-
-    public static final String XML = "+xml";
-    public static final String JSON = "+json";
-    
-    @Deprecated
-    @GET
-    @Path("/datastore")
-    @Produces({Draft01.MediaTypes.DATASTORE+JSON,Draft01.MediaTypes.DATASTORE+XML})
-    public StructuredData readAllData();
-
-    @Deprecated
-    @GET
-    @Path("/datastore/{identifier:.+}")
-    @Produces({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, 
-               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public StructuredData readData(@PathParam("identifier") String identifier);
-
-    @Deprecated
-    @POST
-    @Path("/datastore/{identifier:.+}")
-    @Consumes({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, 
-               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public Response createConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
-
-    @Deprecated
-    @PUT
-    @Path("/datastore/{identifier:.+}")
-    @Consumes({Draft01.MediaTypes.DATA+JSON,Draft01.MediaTypes.DATA+XML, 
-               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
-    public Response updateConfigurationDataLegacy(@PathParam("identifier") String identifier, CompositeNode payload);
-
-}
index 357b599..226eff4 100644 (file)
@@ -134,7 +134,7 @@ class JsonMapper {
 
     private DataSchemaNode findFirstSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode) {
         for (DataSchemaNode dsn : dataSchemaNode) {
-            if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
+            if (node.getNodeType().equals(dsn.getQName())) {
                 return dsn;
             } else if (dsn instanceof ChoiceNode) {
                 for (ChoiceCaseNode choiceCase : ((ChoiceNode) dsn).getCases()) {
@@ -252,14 +252,18 @@ class JsonMapper {
             result.append("/");
 
             writeModuleNameAndIdentifier(result, identityValue);
-            if (identityValue.getPredicates() != null) {
+            if (identityValue.getPredicates() != null && !identityValue.getPredicates().isEmpty()) {
                 for (Predicate predicate : identityValue.getPredicates()) {
                     IdentityValue identityValuePredicate = predicate.getName();
                     result.append("[");
-                    writeModuleNameAndIdentifier(result, identityValuePredicate);
-                    result.append("=\"");
+                    if (identityValuePredicate == null) {
+                        result.append(".");
+                    } else {
+                        writeModuleNameAndIdentifier(result, identityValuePredicate);
+                    }
+                    result.append("='");
                     result.append(predicate.getValue());
-                    result.append("\"");
+                    result.append("'");
                     result.append("]");
                 }
             }
@@ -300,10 +304,16 @@ class JsonMapper {
         String nameForOutput = node.getNodeType().getLocalName();
         if (schema.isAugmenting()) {
             ControllerContext contContext = ControllerContext.getInstance();
-            CharSequence moduleName;
-            moduleName = contContext.toRestconfIdentifier(schema.getQName());
+            CharSequence moduleName = null;
+            if (mountPoint == null) {
+                moduleName = contContext.toRestconfIdentifier(schema.getQName());
+            } else {
+                moduleName = contContext.toRestconfIdentifier(mountPoint, schema.getQName());
+            }
             if (moduleName != null) {
                 nameForOutput = moduleName.toString();
+            } else {
+                logger.info("Module '{}' was not found in schema from mount point", schema.getQName());
             }
         }
         writer.name(nameForOutput);
index f399570..0d73485 100644 (file)
@@ -20,13 +20,12 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.Provider;
 
-import org.opendaylight.controller.sal.rest.api.Draft01;
 import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 @Provider
-@Consumes({ Draft01.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON,
+@Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
         MediaType.APPLICATION_JSON })
 public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
index e4c4993..22e08d9 100644 (file)
@@ -21,7 +21,6 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
-import org.opendaylight.controller.sal.rest.api.Draft01;
 import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.controller.sal.restconf.impl.ResponseException;
@@ -32,7 +31,7 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import com.google.gson.stream.JsonWriter;
 
 @Provider
-@Produces({ Draft01.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON,
+@Produces({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
         MediaType.APPLICATION_JSON })
 public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
index bbe156d..b6d8c95 100644 (file)
@@ -26,7 +26,6 @@ import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
-import org.opendaylight.controller.sal.rest.api.Draft01;
 import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.controller.sal.restconf.impl.ResponseException;
@@ -38,7 +37,7 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
 @Provider
-@Produces({ Draft01.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML,
+@Produces({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
         MediaType.APPLICATION_XML, MediaType.TEXT_XML })
 public enum StructuredDataToXmlProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
index f034312..13d6170 100644 (file)
@@ -21,14 +21,13 @@ import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.Provider;
 import javax.xml.stream.XMLStreamException;
 
-import org.opendaylight.controller.sal.rest.api.Draft01;
 import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.controller.sal.restconf.impl.ResponseException;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 @Provider
-@Consumes({ Draft01.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML,
+@Consumes({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
         MediaType.APPLICATION_XML, MediaType.TEXT_XML })
 public enum XmlToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
index 7d32194..2dfe506 100644 (file)
@@ -216,13 +216,20 @@ class ControllerContext implements SchemaServiceListener {
         var module = uriToModuleName.get(qname.namespace)
         if (module === null) {
             val moduleSchema = globalSchema.findModuleByNamespaceAndRevision(qname.namespace, qname.revision);
-            if(moduleSchema === null) throw new IllegalArgumentException()
+            if(moduleSchema === null) return null
             uriToModuleName.put(qname.namespace, moduleSchema.name)
             module = moduleSchema.name;
         }
         return '''«module»:«qname.localName»''';
     }
 
+    def CharSequence toRestconfIdentifier(MountInstance mountPoint, QName qname) {
+        val moduleSchema = mountPoint?.schemaContext.findModuleByNamespaceAndRevision(qname.namespace, qname.revision);
+        if(moduleSchema === null) return null
+        val module = moduleSchema.name;
+        return '''«module»:«qname.localName»''';
+    }
+
     private static dispatch def DataSchemaNode childByQName(ChoiceNode container, QName name) {
         for (caze : container.cases) {
             val ret = caze.childByQName(name)
index 4f643fe..d6b5300 100644 (file)
@@ -212,6 +212,11 @@ public class RestCodec {
                     List<Predicate> predicates = keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument)
                             .getKeyValues());
                     identityValue.setPredicates(predicates);
+                } else if (pathArgument instanceof NodeWithValue && identityValue != null) {
+                    List<Predicate> predicates = new ArrayList<>();
+                    String value = String.valueOf(((NodeWithValue) pathArgument).getValue());
+                    predicates.add(new Predicate(null, value));
+                    identityValue.setPredicates(predicates);
                 }
                 identityValuesDTO.add(identityValue);
             }
index 07fb05a..cbfc3ed 100644 (file)
@@ -58,12 +58,6 @@ class RestconfImpl implements RestconfService {
         return INSTANCE
     }
 
-    override readAllData() {
-
-        //        return broker.readOperationalData("".toInstanceIdentifier.getInstanceIdentifier);
-        throw new UnsupportedOperationException("Reading all data is currently not supported.")
-    }
-
     override getModules() {
         throw new UnsupportedOperationException("TODO: auto-generated method stub")
     }
@@ -76,7 +70,10 @@ class RestconfImpl implements RestconfService {
         return callRpc(identifier.rpcDefinition, payload)
     }
 
-    override invokeRpc(String identifier) {
+    override invokeRpc(String identifier, String noPayload) {
+        if (!noPayload.nullOrEmpty) {
+            throw new ResponseException(UNSUPPORTED_MEDIA_TYPE, "Content-Type contains unsupported Media Type.");
+        }
         return callRpc(identifier.rpcDefinition, null)
     }
 
@@ -103,17 +100,6 @@ class RestconfImpl implements RestconfService {
         return new StructuredData(rpcResult.result, rpc.output, null)
     }
 
-    override readData(String identifier) {
-        val iiWithData = identifier.toInstanceIdentifier
-        var CompositeNode data = null;
-        if (iiWithData.mountPoint !== null) {
-            data = broker.readOperationalDataBehindMountPoint(iiWithData.mountPoint, iiWithData.instanceIdentifier)
-        } else {
-            data = broker.readOperationalData(iiWithData.getInstanceIdentifier);
-        }
-        return new StructuredData(data, iiWithData.schemaNode, iiWithData.mountPoint)
-    }
-
     override readConfigurationData(String identifier) {
         val iiWithData = identifier.toInstanceIdentifier
         var CompositeNode data = null;
@@ -136,10 +122,6 @@ class RestconfImpl implements RestconfService {
         return new StructuredData(data, iiWithData.schemaNode, iiWithData.mountPoint)
     }
 
-    override updateConfigurationDataLegacy(String identifier, CompositeNode payload) {
-        updateConfigurationData(identifier, payload);
-    }
-
     override updateConfigurationData(String identifier, CompositeNode payload) {
         val iiWithData = identifier.toInstanceIdentifier
         val value = normalizeNode(payload, iiWithData.schemaNode, iiWithData.mountPoint)
@@ -156,10 +138,6 @@ class RestconfImpl implements RestconfService {
         }
     }
 
-    override createConfigurationDataLegacy(String identifier, CompositeNode payload) {
-        createConfigurationData(identifier, payload);
-    }
-
     override createConfigurationData(String identifier, CompositeNode payload) {
         if (payload.namespace === null) {
             throw new ResponseException(BAD_REQUEST,
index f361296..874e8b0 100644 (file)
@@ -51,6 +51,7 @@ public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader {
      * Test of json output when as input are specified composite node with empty
      * data + YANG file
      */
+
     @Test
     public void compositeNodeAndYangWithJsonReaderEmptyDataTest() {
         CompositeNode compositeNode = prepareCompositeNodeWithEmpties();
@@ -538,49 +539,49 @@ public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader {
                 TestUtils.buildQName("cont1", "simple:yang:types", "2013-11-5"), null, null, ModifyAction.CREATE, null);
 
         // lst11_1
-        MutableCompositeNode lst11_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst11"), cont1,
+        MutableCompositeNode lst11_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst11","simple:yang:types","2013-11-5"), cont1,
                 null, ModifyAction.CREATE, null);
         cont1.getChildren().add(lst11_1);
 
-        MutableSimpleNode<?> lf111_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_1,
+        MutableSimpleNode<?> lf111_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111","simple:yang:types","2013-11-5"), lst11_1,
                 (short) 1, ModifyAction.CREATE, null);
         lst11_1.getChildren().add(lf111_1);
 
         // lst111_1_1
-        MutableCompositeNode lst111_1_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111"),
+        MutableCompositeNode lst111_1_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111","simple:yang:types","2013-11-5"),
                 lst11_1, null, ModifyAction.CREATE, null);
         lst11_1.getChildren().add(lst111_1_1);
-        MutableSimpleNode<?> lf1111_1_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111"),
+        MutableSimpleNode<?> lf1111_1_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111","simple:yang:types","2013-11-5"),
                 lst111_1_1, (int) 34, ModifyAction.CREATE, null);
         lst111_1_1.getChildren().add(lf1111_1_1);
         lst111_1_1.init();
         // :lst111_1_1
 
         // lst111_1_2
-        MutableCompositeNode lst111_1_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111"),
+        MutableCompositeNode lst111_1_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111","simple:yang:types","2013-11-5"),
                 lst11_1, null, ModifyAction.CREATE, null);
         lst11_1.getChildren().add(lst111_1_2);
-        MutableSimpleNode<?> lf1111_1_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111"),
+        MutableSimpleNode<?> lf1111_1_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111","simple:yang:types","2013-11-5"),
                 lst111_1_2, (int) 35, ModifyAction.CREATE, null);
         lst111_1_2.getChildren().add(lf1111_1_2);
         lst111_1_2.init();
         // :lst111_1_2
 
         // lst111_1_3
-        MutableCompositeNode lst111_1_3 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111"),
+        MutableCompositeNode lst111_1_3 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111","simple:yang:types","2013-11-5"),
                 lst11_1, null, ModifyAction.CREATE, null);
         lst11_1.getChildren().add(lst111_1_3);
         lst111_1_2.init();
         // :lst111_1_3
 
         // lst111_1_4
-        MutableCompositeNode lst111_1_4 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111"),
+        MutableCompositeNode lst111_1_4 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst111","simple:yang:types","2013-11-5"),
                 lst11_1, null, ModifyAction.CREATE, null);
         lst11_1.getChildren().add(lst111_1_4);
         lst111_1_2.init();
         // :lst111_1_4
 
-        MutableCompositeNode cont111_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont111"),
+        MutableCompositeNode cont111_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont111","simple:yang:types","2013-11-5"),
                 lst11_1, null, ModifyAction.CREATE, null);
         lst11_1.getChildren().add(cont111_1);
 
@@ -588,39 +589,39 @@ public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader {
         // :lst11_1
 
         // lst11_2
-        MutableCompositeNode lst11_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst11"), cont1,
+        MutableCompositeNode lst11_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst11","simple:yang:types","2013-11-5"), cont1,
                 null, ModifyAction.CREATE, null);
         cont1.getChildren().add(lst11_2);
 
-        MutableSimpleNode<?> lf111_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_2,
+        MutableSimpleNode<?> lf111_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111","simple:yang:types","2013-11-5"), lst11_2,
                 (short) 2, ModifyAction.CREATE, null);
         lst11_2.getChildren().add(lf111_2);
 
         // cont111_2
-        MutableCompositeNode cont111_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont111"),
+        MutableCompositeNode cont111_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont111","simple:yang:types","2013-11-5"),
                 lst11_2, null, ModifyAction.CREATE, null);
         lst11_2.getChildren().add(cont111_2);
 
-        MutableSimpleNode<?> lflst1111_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111"),
+        MutableSimpleNode<?> lflst1111_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111","simple:yang:types","2013-11-5"),
                 cont111_2, (int) 1024, ModifyAction.CREATE, null);
         cont111_2.getChildren().add(lflst1111_2_2);
-        MutableSimpleNode<?> lflst1111_2_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111"),
+        MutableSimpleNode<?> lflst1111_2_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lflst1111","simple:yang:types","2013-11-5"),
                 cont111_2, (int) 4096, ModifyAction.CREATE, null);
         cont111_2.getChildren().add(lflst1111_2_3);
 
         // lst1111_2
-        MutableCompositeNode lst1111_2_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111"),
+        MutableCompositeNode lst1111_2_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111","simple:yang:types","2013-11-5"),
                 cont111_2, null, ModifyAction.CREATE, null);
         cont111_2.getChildren().add(lst1111_2_1);
-        MutableSimpleNode<?> lf1111B_2_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111B"),
+        MutableSimpleNode<?> lf1111B_2_1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111B","simple:yang:types","2013-11-5"),
                 lst1111_2_1, (short) 4, ModifyAction.CREATE, null);
         lst1111_2_1.getChildren().add(lf1111B_2_1);
         lst1111_2_1.init();
 
-        MutableCompositeNode lst1111_2_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111"),
+        MutableCompositeNode lst1111_2_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111","simple:yang:types","2013-11-5"),
                 cont111_2, null, ModifyAction.CREATE, null);
         cont111_2.getChildren().add(lst1111_2_2);
-        MutableSimpleNode<?> lf1111A_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111A"),
+        MutableSimpleNode<?> lf1111A_2_2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1111A","simple:yang:types","2013-11-5"),
                 lst1111_2_2, "lf1111A str12", ModifyAction.CREATE, null);
         lst1111_2_2.getChildren().add(lf1111A_2_2);
         lst1111_2_2.init();
@@ -629,7 +630,7 @@ public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader {
         cont111_2.init();
         // :cont111_2
 
-        MutableCompositeNode lst112_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst112"), lst11_2,
+        MutableCompositeNode lst112_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst112","simple:yang:types","2013-11-5"), lst11_2,
                 null, ModifyAction.CREATE, null);
         lst11_2.getChildren().add(lst112_2);
         lst112_2.init();
@@ -638,25 +639,25 @@ public class CnSnJsonBasicYangTypesTest extends YangAndXmlAndDataSchemaLoader {
         // :lst11_2
 
         // lst11_3
-        MutableCompositeNode lst11_3 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst11"), cont1,
+        MutableCompositeNode lst11_3 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst11","simple:yang:types","2013-11-5"), cont1,
                 null, ModifyAction.CREATE, null);
         cont1.getChildren().add(lst11_3);
 
-        MutableSimpleNode<?> lf111_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111"), lst11_3,
+        MutableSimpleNode<?> lf111_3 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111","simple:yang:types","2013-11-5"), lst11_3,
                 (short) 3, ModifyAction.CREATE, null);
         lst11_3.getChildren().add(lf111_3);
 
         // cont111_3
-        MutableCompositeNode cont111_3 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont111"),
+        MutableCompositeNode cont111_3 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont111","simple:yang:types","2013-11-5"),
                 lst11_3, null, ModifyAction.CREATE, null);
         lst11_3.getChildren().add(cont111_3);
 
-        MutableCompositeNode lst1111_3_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111"),
+        MutableCompositeNode lst1111_3_1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111","simple:yang:types","2013-11-5"),
                 cont111_3, null, ModifyAction.CREATE, null);
         cont111_3.getChildren().add(lst1111_3_1);
         lst1111_3_1.init();
 
-        MutableCompositeNode lst1111_3_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111"),
+        MutableCompositeNode lst1111_3_2 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("lst1111","simple:yang:types","2013-11-5"),
                 cont111_3, null, ModifyAction.CREATE, null);
         cont111_3.getChildren().add(lst1111_3_2);
         lst1111_3_2.init();
index d664001..745f11c 100644 (file)
@@ -22,7 +22,10 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
 import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 
 public class CnSnToJsonIdentityrefTest extends YangAndXmlAndDataSchemaLoader {
@@ -71,13 +74,13 @@ public class CnSnToJsonIdentityrefTest extends YangAndXmlAndDataSchemaLoader {
     }
 
     private CompositeNode prepareCompositeNode(Object value) {
-        MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null,
+        MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont","identityref:module","2013-12-2"), null, null,
                 ModifyAction.CREATE, null);
-        MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont1"), cont, null,
+        MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont1","identityref:module","2013-12-2"), cont, null,
                 ModifyAction.CREATE, null);
         cont.getChildren().add(cont1);
 
-        MutableSimpleNode<?> lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1"), cont1, value,
+        MutableSimpleNode<?> lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1","identityref:module","2013-12-2"), cont1, value,
                 ModifyAction.CREATE, null);
 
         cont1.getChildren().add(lf1);
index d1e55c7..050a992 100644 (file)
@@ -33,7 +33,6 @@ import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UsesNode;
-import org.opendaylight.yangtools.yang.model.api.YangNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index d1dca95..17d7fe6 100644 (file)
@@ -20,8 +20,13 @@ import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
-import org.opendaylight.controller.sal.restconf.impl.test.*;
-import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.controller.sal.restconf.impl.test.DummyType;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
@@ -39,20 +44,13 @@ public class CnSnToJsonNotExistingLeafTypeTest extends YangAndXmlAndDataSchemaLo
         dataLoad("/cnsn-to-json/simple-data-types");
     }
 
-    // FIXME
-    @Ignore
     @Test
-    public void incorrectTopLevelElementTest() {
-
+    public void incorrectTopLevelElementTest() throws WebApplicationException, IOException {
         String jsonOutput = null;
-        try {
-            jsonOutput = TestUtils
-                    .writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(),
-                            (Set<Module>) Collections.EMPTY_SET, prepareDataSchemaNode(),
-                            StructuredDataToJsonProvider.INSTANCE);
-        } catch (WebApplicationException | IOException e) {
-            LOG.error("WebApplicationException or IOException was raised");
-        }
+        jsonOutput = TestUtils
+                .writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(),
+                        (Set<Module>) Collections.EMPTY_SET, prepareDataSchemaNode(),
+                        StructuredDataToJsonProvider.INSTANCE);
         assertNotNull(jsonOutput);
         assertTrue(jsonOutput.contains("\"lf1\": \"\""));
     }
index baefd93..348edbd 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -20,19 +19,19 @@ import javax.ws.rs.WebApplicationException;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
-import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
-import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
 import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 public class CnSnToJsonWithDataFromSeveralModulesTest extends YangAndXmlAndDataSchemaLoader {
 
     @BeforeClass
     public static void initialize() {
-        dataLoad("/xml-to-cnsn/data-of-several-modules/yang",2,"module1","cont_m1");
+        dataLoad("/xml-to-cnsn/data-of-several-modules/yang", 2, "module1", "cont_m1");
     }
 
     @Test
@@ -41,15 +40,15 @@ public class CnSnToJsonWithDataFromSeveralModulesTest extends YangAndXmlAndDataS
         String output = TestUtils.writeCompNodeWithSchemaContextToOutput(prepareCnSn(), modules, schemaContext,
                 StructuredDataToJsonProvider.INSTANCE);
 
-//         String output =
-//         String.format("\"data\"   :   {\n" +
-//                             "\t\"cont_m1\"   :  {\n" +
-//                                 "\t\t\"lf1_m1\"   :  \"lf1 m1 value\"\n" +
-//                             "\t}\n" +
-//                             "\t\"cont_m2\"   :  {\n" +
-//                                 "\t\t\"lf1_m2\"   :  \"lf1 m2 value\"\n" +
-//                             "\t}\n" +
-//                     "}");
+        // String output =
+        // String.format("\"data\"   :   {\n" +
+        // "\t\"cont_m1\"   :  {\n" +
+        // "\t\t\"lf1_m1\"   :  \"lf1 m1 value\"\n" +
+        // "\t}\n" +
+        // "\t\"cont_m2\"   :  {\n" +
+        // "\t\t\"lf1_m2\"   :  \"lf1 m2 value\"\n" +
+        // "\t}\n" +
+        // "}");
 
         StringBuilder regex = new StringBuilder();
         regex.append("^");
@@ -57,27 +56,27 @@ public class CnSnToJsonWithDataFromSeveralModulesTest extends YangAndXmlAndDataS
         regex.append(".*\"data\"");
         regex.append(".*:");
         regex.append(".*\\{");
-        
-        regex.append(".*\"contB_m1\"");
+
+        regex.append(".*\"cont_m1\"");
         regex.append(".*:");
         regex.append(".*\\{");
         regex.append(".*\\}");
-        
-        regex.append(".*\"cont_m1\"");
+
+        regex.append(".*\"contB_m1\"");
         regex.append(".*:");
         regex.append(".*\\{");
         regex.append(".*\\}");
 
-        regex.append(".*\"contB_m2\"");
+        regex.append(".*\"cont_m2\"");
         regex.append(".*:");
         regex.append(".*\\{");
         regex.append(".*\\}");
-        
-        regex.append(".*\"cont_m2\"");
+
+        regex.append(".*\"contB_m2\"");
         regex.append(".*:");
         regex.append(".*\\{");
         regex.append(".*\\}");
-        
+
         regex.append(".*\\}");
 
         regex.append(".*");
@@ -91,24 +90,44 @@ public class CnSnToJsonWithDataFromSeveralModulesTest extends YangAndXmlAndDataS
     }
 
     private CompositeNode prepareCnSn() throws URISyntaxException {
-        CompositeNodeWrapper data = new CompositeNodeWrapper(new URI("urn:ietf:params:xml:ns:netconf:base:1.0"), "data");
-
-        URI uriModule1 = new URI("module:one");
-        CompositeNodeWrapper cont_m1 = new CompositeNodeWrapper(uriModule1, "cont_m1");
-        SimpleNodeWrapper lf1_m1 = new SimpleNodeWrapper(uriModule1, "lf1_m1", "lf1 m1 value");
-        cont_m1.addValue(lf1_m1);
-        CompositeNodeWrapper contB_m1 = new CompositeNodeWrapper(uriModule1, "contB_m1");
-        
-        data.addValue(contB_m1);
-        data.addValue(cont_m1);
-
-        URI uriModule2 = new URI("module:two");
-        CompositeNodeWrapper cont_m2 = new CompositeNodeWrapper(uriModule2, "cont_m2");
-        SimpleNodeWrapper lf1_m2 = new SimpleNodeWrapper(uriModule2, "lf1_m2", "lf1 m2 value");
-        cont_m2.addValue(lf1_m2);
-        CompositeNodeWrapper contB_m2 = new CompositeNodeWrapper(uriModule2, "contB_m2");
-        data.addValue(contB_m2);
-        data.addValue(cont_m2);
+        String uri1 = "module:one";
+        String rev1 = "2014-01-17";
+
+        MutableCompositeNode data = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("data", "urn:ietf:params:xml:ns:netconf:base:1.0", "2000-01-01"), null, null,
+                null, null);
+
+        MutableCompositeNode cont_m1 = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("cont_m1", uri1, rev1), data, null, null, null);
+        data.getChildren().add(cont_m1);
+
+        MutableSimpleNode<?> lf1_m1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1_m1", uri1, rev1),
+                cont_m1, "lf1 m1 value", null, null);
+        cont_m1.getChildren().add(lf1_m1);
+        cont_m1.init();
+
+        MutableCompositeNode contB_m1 = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("contB_m1", uri1, rev1), data, null, null, null);
+        data.getChildren().add(contB_m1);
+        contB_m1.init();
+
+        String uri2 = "module:two";
+        String rev2 = "2014-01-17";
+        MutableCompositeNode cont_m2 = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("cont_m2", uri2, rev2), data, null, null, null);
+        data.getChildren().add(cont_m2);
+
+        MutableSimpleNode<?> lf1_m2 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf1_m2", uri2, rev2),
+                cont_m1, "lf1 m2 value", null, null);
+        cont_m2.getChildren().add(lf1_m2);
+        cont_m2.init();
+
+        MutableCompositeNode contB_m2 = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("contB_m2", uri2, rev2), data, null, null, null);
+        data.getChildren().add(contB_m2);
+        contB_m2.init();
+
+        data.init();
         return data;
     }
 
index 5a81b32..92de14b 100644 (file)
@@ -35,7 +35,7 @@ public class CnSnInstanceIdentifierToXmlTest extends YangAndXmlAndDataSchemaLoad
     
     @BeforeClass
     public static void initialization() throws URISyntaxException {
-        dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont");
+        dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
     }
 
     @Test
index 7da572f..18b5ce4 100644 (file)
@@ -28,43 +28,87 @@ import javax.xml.stream.events.StartElement;
 import javax.xml.stream.events.XMLEvent;
 
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
-import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 
 public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
 
     @BeforeClass
     public static void initialize() {
-        dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont");
+        dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
     }
 
     @Test
-    public void saveCnSnToXml() throws WebApplicationException, IOException, URISyntaxException, XMLStreamException {
-        CompositeNode cnSn = prepareCnSn();
+    public void saveCnSnToXmlTest() throws WebApplicationException, IOException, URISyntaxException, XMLStreamException {
+        CompositeNode cnSn = prepareCnSn(createInstanceIdentifier());
         String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
                 StructuredDataToXmlProvider.INSTANCE);
+        //uncomment for debug
+        // System.out.println(output);
         validateXmlOutput(output);
+
+    }
+
+    @Ignore
+    @Test
+    public void saveCnSnWithLeafListInstIdentifierToXmlTest() throws WebApplicationException, IOException,
+            URISyntaxException, XMLStreamException {
+        CompositeNode cnSn = prepareCnSn(createInstanceIdentifierWithLeafList());
+        String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
+                StructuredDataToXmlProvider.INSTANCE);
+        //uncomment for debug
         // System.out.println(output);
+        validateXmlOutputWithLeafList(output);
+    }
+
+    @Test
+    public void saveCnSnToJsonTest() throws WebApplicationException, IOException, URISyntaxException {
+        CompositeNode cnSn = prepareCnSn(createInstanceIdentifier());
+        String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
+                StructuredDataToJsonProvider.INSTANCE);
+        boolean strInOutput = false;
+        strInOutput = output
+                .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\\\"value1\\\"][augment-module:keyvalue112=\\\"value2\\\"]/augment-augment-module:lf112\"");
 
+        if (!strInOutput) {
+            strInOutput = output
+                    .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111='value1'][augment-module:keyvalue112='value2']/augment-augment-module:lf112\"");
+        }
+        //uncomment for debug
+        // System.out.println(output);
+        assertTrue(strInOutput);
     }
 
+
     @Test
-    public void saveCnSnToJson() throws WebApplicationException, IOException, URISyntaxException {
-        CompositeNode cnSn = prepareCnSn();
+    public void saveCnSnWithLeafListInstIdentifierToJsonTest() throws WebApplicationException, IOException,
+            URISyntaxException {
+        CompositeNode cnSn = prepareCnSn(createInstanceIdentifierWithLeafList());
         String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
                 StructuredDataToJsonProvider.INSTANCE);
-        assertTrue(output
-                .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\\\"value1\\\"][augment-module:keyvalue112=\\\"value2\\\"]/augment-augment-module:lf112\""));
+        //uncomment for debug
         // System.out.println(output);
+        boolean strInOutput = false;
+        strInOutput = output
+                .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.='lflst11_1']\"");
+        if (!strInOutput) {
+            strInOutput = output
+                    .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.=\\\"lflst11_1\\\"]\"");
+        }
+
+        assertTrue(strInOutput);
     }
 
     private void validateXmlOutput(String xml) throws XMLStreamException {
@@ -104,21 +148,66 @@ public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSch
                 + ":lst11[" + aModulePrefix + ":keyvalue111='value1'][" + aModulePrefix + ":keyvalue112='value2']/"
                 + aaModulePrefix + ":lf112";
 
-//        System.out.println(xml);
         assertTrue(xml.contains(instanceIdentifierValue));
 
     }
 
-    private CompositeNode prepareCnSn() throws URISyntaxException {
-        CompositeNodeWrapper cont = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont");
-        CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("instance:identifier:module"), "cont1");
-        CompositeNodeWrapper lst11 = new CompositeNodeWrapper(new URI("augment:module"), "lst11");
-        InstanceIdentifier instanceIdentifier = createInstanceIdentifier();
-        SimpleNodeWrapper lf111 = new SimpleNodeWrapper(new URI("augment:augment:module"), "lf111", instanceIdentifier);
+    private void validateXmlOutputWithLeafList(String xml) throws XMLStreamException {
+        XMLInputFactory xmlInFactory = XMLInputFactory.newInstance();
+        XMLEventReader eventReader;
 
-        lst11.addValue(lf111);
-        cont1.addValue(lst11);
-        cont.addValue(cont1);
+        eventReader = xmlInFactory.createXMLEventReader(new ByteArrayInputStream(xml.getBytes()));
+        String aModuleLfLstPrefix = null;
+        String iiModulePrefix = null;
+        while (eventReader.hasNext()) {
+            XMLEvent nextEvent = eventReader.nextEvent();
+            if (nextEvent.isStartElement()) {
+                StartElement startElement = (StartElement) nextEvent;
+                if (startElement.getName().getLocalPart().equals("lf111")) {
+                    Iterator prefixes = startElement.getNamespaceContext().getPrefixes("augment:module:leaf:list");
+
+                    while (prefixes.hasNext() && aModuleLfLstPrefix == null) {
+                        String prefix = (String) prefixes.next();
+                        if (!prefix.isEmpty()) {
+                            aModuleLfLstPrefix = prefix;
+                        }
+                    }
+                    iiModulePrefix = startElement.getNamespaceContext().getPrefix("instance:identifier:module");
+                    break;
+                }
+            }
+        }
+
+        assertNotNull(aModuleLfLstPrefix);
+        assertNotNull(iiModulePrefix);
+
+        String instanceIdentifierValue = "/" + iiModulePrefix + ":cont/" + iiModulePrefix + ":cont1/"
+                + aModuleLfLstPrefix + ":lflst11[.='lflst11_1']";
+
+        assertTrue(xml.contains(instanceIdentifierValue));
+
+    }
+
+    private CompositeNode prepareCnSn(InstanceIdentifier instanceIdentifier) throws URISyntaxException {
+        MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("cont", "instance:identifier:module", "2014-01-17"), null, null,null,null);
+        MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("cont1", "instance:identifier:module", "2014-01-17"), cont, null,null,null);
+        MutableCompositeNode lst11 = NodeFactory.createMutableCompositeNode(
+                TestUtils.buildQName("lst11", "augment:module", "2014-01-17"), cont1, null,null,null);
+
+        MutableSimpleNode<?> lf111 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111", "augment:augment:module", "2014-01-17"),
+                lst11, instanceIdentifier,null,null);
+        
+        
+        lst11.getChildren().add(lf111);
+        lst11.init();
+
+        cont1.getChildren().add(lst11);
+        cont1.init();
+        
+        cont.getChildren().add(cont1);
+        cont.init();
 
         return cont;
     }
@@ -140,4 +229,13 @@ public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSch
         return new InstanceIdentifier(pathArguments);
     }
 
+    private InstanceIdentifier createInstanceIdentifierWithLeafList() throws URISyntaxException {
+        List<PathArgument> pathArguments = new ArrayList<>();
+        pathArguments.add(new NodeIdentifier(new QName(new URI("instance:identifier:module"), "cont")));
+        pathArguments.add(new NodeIdentifier(new QName(new URI("instance:identifier:module"), "cont1")));
+        pathArguments.add(new NodeWithValue(new QName(new URI("augment:module:leaf:list"), "lflst11"), "lflst11_1"));
+
+        return new InstanceIdentifier(pathArguments);
+    }
+
 }
index 2a8ab7a..e1d7e6a 100644 (file)
@@ -72,9 +72,9 @@ public class MediaTypesTest extends JerseyTest {
       String uriPath = "ietf-interfaces:interfaces";
       String uri = createUri(uriPrefix, uriPath);
       when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
-      post(uri, Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+JSON, jsonData);
+      post(uri, Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+JSON, jsonData);
       verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class));
-      post(uri, Draft02.MediaTypes.DATA+XML, Draft02.MediaTypes.DATA+XML, xmlData);
+      post(uri, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.OPERATION+XML, xmlData);
       verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(CompositeNode.class));
       post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData);
       verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(CompositeNode.class));
index 76ec65c..be7be94 100644 (file)
@@ -11,7 +11,6 @@ import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
 import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
 
 import java.io.FileNotFoundException;
@@ -20,21 +19,16 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.logging.Level;
 
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
 
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
-import org.glassfish.jersey.test.TestProperties;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountService;
-import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
@@ -84,24 +78,6 @@ public class RestGetOperationTest extends JerseyTest {
         return resourceConfig;
     }
 
-    /**
-     * Tests of status codes for "/datastore/{identifier}".
-     */
-    @Test
-    public void getDatastoreStatusCodes() throws FileNotFoundException, UnsupportedEncodingException {
-        mockReadOperationalDataMethod();
-        String uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
-        assertEquals(200, get(uri, MediaType.APPLICATION_XML));
-
-        uri = createUri("/datastore/", "wrong-module:interfaces/interface/eth0");
-        assertEquals(400, get(uri, MediaType.APPLICATION_XML));
-
-        // Test of request for not existing data. Returning status code 404
-        uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
-        when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(null);
-        assertEquals(404, get(uri, MediaType.APPLICATION_XML));
-    }
-
     /**
      * Tests of status codes for "/operational/{identifier}".
      */
index ab63fbc..050aa9a 100644 (file)
@@ -14,7 +14,6 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -29,7 +28,6 @@ import java.util.concurrent.Future;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
 
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
@@ -43,7 +41,6 @@ import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
-import org.opendaylight.controller.sal.rest.impl.XmlMapper;
 import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
@@ -153,20 +150,6 @@ public class RestPostOperationTest extends JerseyTest {
         assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath));
     }
 
-    @Test
-    public void postDatastoreStatusCodes() throws UnsupportedEncodingException {
-        controllerContext.setSchemas(schemaContextYangsIetf);
-        mockCommitConfigurationDataPostMethod(TransactionStatus.COMMITED);
-        String uri = createUri("/datastore/", "ietf-interfaces:interfaces");
-        assertEquals(204, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath));
-
-        mockCommitConfigurationDataPostMethod(null);
-        assertEquals(202, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath));
-
-        mockCommitConfigurationDataPostMethod(TransactionStatus.FAILED);
-        assertEquals(500, post(uri, MediaType.APPLICATION_XML, xmlDataInterfaceAbsolutePath));
-    }
-
     @Test
     public void postDataViaUrlMountPoint() throws UnsupportedEncodingException {
         controllerContext.setSchemas(schemaContextYangsIetf);
index 5d7eb20..2ba4a38 100644 (file)
@@ -11,7 +11,6 @@ import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
 import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
 
 import java.io.FileNotFoundException;
@@ -24,17 +23,14 @@ import java.util.concurrent.Future;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
 
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountService;
-import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
@@ -107,19 +103,6 @@ public class RestPutOperationTest extends JerseyTest {
         assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
     }
 
-    /**
-     * Tests of status codes for "/datastore/{identifier}".
-     */
-    @Test
-    public void putDatastoreStatusCodes() throws UnsupportedEncodingException {
-        String uri = createUri("/datastore/", "ietf-interfaces:interfaces/interface/eth0");
-        mockCommitConfigurationDataPutMethod(TransactionStatus.COMMITED);
-        assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData));
-
-        mockCommitConfigurationDataPutMethod(TransactionStatus.FAILED);
-        assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
-    }
-
     @Test
     public void testRpcResultCommitedToStatusCodesWithMountPoint() throws UnsupportedEncodingException,
             FileNotFoundException, URISyntaxException {
@@ -131,10 +114,6 @@ public class RestPutOperationTest extends JerseyTest {
                 brokerFacade.commitConfigurationDataPutBehindMountPoint(any(MountInstance.class),
                         any(InstanceIdentifier.class), any(CompositeNode.class))).thenReturn(dummyFuture);
 
-        InputStream xmlStream = RestconfImplTest.class.getResourceAsStream("/full-versions/test-data2/data2.xml");
-        String xml = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream));
-        Entity<String> entity = Entity.entity(xml, Draft02.MediaTypes.DATA + XML);
-
         MountInstance mountInstance = mock(MountInstance.class);
         when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
         MountService mockMountService = mock(MountService.class);
index e8d03fb..5476d71 100644 (file)
@@ -26,6 +26,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 
@@ -33,7 +34,7 @@ public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSch
 
     @BeforeClass
     public static void initialize() {
-        dataLoad("/instanceidentifier/yang", 3, "instance-identifier-module", "cont");
+        dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
     }
 
     @Test
@@ -41,7 +42,15 @@ public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSch
         CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata.xml",
                 XmlToCompositeNodeProvider.INSTANCE);
         TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath);
-        verify(cnSn);
+        verifyListPredicate(cnSn);
+    }
+
+    @Test
+    public void loadXmlLeafListToCnSn() throws WebApplicationException, IOException, URISyntaxException {
+        CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/xml/xmldata_leaf_list.xml",
+                XmlToCompositeNodeProvider.INSTANCE);
+        TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath);
+        verifyLeafListPredicate(cnSn);
     }
 
     @Test
@@ -49,11 +58,40 @@ public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSch
         CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata.json",
                 JsonToCompositeNodeProvider.INSTANCE);
         TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath);
-        verify(cnSn);
+        verifyListPredicate(cnSn);
     }
 
-    private void verify(CompositeNode cnSn) throws URISyntaxException {
-        SimpleNode<?> lf111 = getSnWithInstanceIdentifier(cnSn);
+    @Test
+    public void loadJsonLeafListToCnSn() throws WebApplicationException, IOException, URISyntaxException {
+        CompositeNode cnSn = TestUtils.readInputToCnSn("/instanceidentifier/json/jsondata_leaf_list.json",
+                JsonToCompositeNodeProvider.INSTANCE);
+        TestUtils.normalizeCompositeNode(cnSn, modules, schemaNodePath);
+        verifyLeafListPredicate(cnSn);
+    }
+
+    private void verifyLeafListPredicate(CompositeNode cnSn) throws URISyntaxException {
+        SimpleNode<?> lf11 = getSnWithInstanceIdentifierWhenLeafList(cnSn);
+        Object value = lf11.getValue();
+        assertTrue(value instanceof InstanceIdentifier);
+
+        InstanceIdentifier instanceIdentifier = (InstanceIdentifier) value;
+        List<PathArgument> pathArguments = instanceIdentifier.getPath();
+        assertEquals(3, pathArguments.size());
+        String revisionDate = "2014-01-17";
+        assertEquals(TestUtils.buildQName("cont", "instance:identifier:module", revisionDate), pathArguments.get(0)
+                .getNodeType());
+        assertEquals(TestUtils.buildQName("cont1", "instance:identifier:module", revisionDate), pathArguments.get(1)
+                .getNodeType());
+        assertEquals(TestUtils.buildQName("lflst11", "augment:module:leaf:list", "2014-01-27"), pathArguments.get(2)
+                .getNodeType());
+
+        assertTrue(pathArguments.get(2) instanceof NodeWithValue);
+        assertEquals("lflst11_1", ((NodeWithValue) pathArguments.get(2)).getValue());
+
+    }
+
+    private void verifyListPredicate(CompositeNode cnSn) throws URISyntaxException {
+        SimpleNode<?> lf111 = getSnWithInstanceIdentifierWhenList(cnSn);
         Object value = lf111.getValue();
         assertTrue(value instanceof InstanceIdentifier);
 
@@ -76,7 +114,7 @@ public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSch
         assertEquals("value2", predicates.get(TestUtils.buildQName("keyvalue112", "augment:module", revisionDate)));
     }
 
-    private SimpleNode<?> getSnWithInstanceIdentifier(CompositeNode cnSn) throws URISyntaxException {
+    private SimpleNode<?> getSnWithInstanceIdentifierWhenList(CompositeNode cnSn) throws URISyntaxException {
         CompositeNode cont1 = cnSn.getFirstCompositeByName(TestUtils.buildQName("cont1", "instance:identifier:module",
                 "2014-01-17"));
         assertNotNull(cont1);
@@ -89,4 +127,14 @@ public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSch
         return lf111;
     }
 
+    private SimpleNode<?> getSnWithInstanceIdentifierWhenLeafList(CompositeNode cnSn) throws URISyntaxException {
+        CompositeNode cont1 = cnSn.getFirstCompositeByName(TestUtils.buildQName("cont1", "instance:identifier:module",
+                "2014-01-17"));
+        assertNotNull(cont1);
+        SimpleNode<?> lf11 = cont1.getFirstSimpleByName(TestUtils.buildQName("lf11", "augment:module:leaf:list",
+                "2014-01-27"));
+        assertNotNull(lf11);
+        return lf11;
+    }
+
 }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata_leaf_list.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/json/jsondata_leaf_list.json
new file mode 100644 (file)
index 0000000..63be4b9
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "instance-identifier-module:cont": {
+        "cont1": {
+            "augment-module-leaf-list:lf11" : "/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.=\"lflst11_1\"]"
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata_leaf_list.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata_leaf_list.xml
new file mode 100644 (file)
index 0000000..00d58c2
--- /dev/null
@@ -0,0 +1,8 @@
+<cont xmlns="instance:identifier:module">
+    <cont1>
+        <lflst11 xmlns="augment:module:leaf:list">lflst11_1</lflst11>
+        <lflst11 xmlns="augment:module:leaf:list">lflst11_2</lflst11>
+        <lflst11 xmlns="augment:module:leaf:list">lflst11_3</lflst11>
+        <lf11 xmlns:a="instance:identifier:module" xmlns:b="augment:module:leaf:list" xmlns="augment:module:leaf:list">/a:cont/a:cont1/b:lflst11[.="lflst11_1"]</lf11>
+    </cont1>
+</cont>
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module-leaf-list.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/yang/augment-module-leaf-list.yang
new file mode 100644 (file)
index 0000000..54c305b
--- /dev/null
@@ -0,0 +1,20 @@
+module augment-module-leaf-list {
+  namespace "augment:module:leaf:list";  
+
+  prefix "amodulelflst";  
+  
+  import instance-identifier-module {prefix imodule; revision-date 2014-01-17;}
+   
+  revision 2014-01-27 {    
+  }
+  
+    augment "/imodule:cont/imodule:cont1" {
+       leaf-list lflst11 {
+           type string;
+       }       
+       leaf lf11 {
+            type instance-identifier;
+       }
+    }   
+         
+}
\ No newline at end of file
index 8c95545..599fd71 100644 (file)
@@ -45,7 +45,7 @@
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>${yang.codegen.version}</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index 19f2594..5f264ab 100644 (file)
@@ -412,8 +412,6 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
                 cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
             }
             NodeStatisticsAger nsa = cache.get(notification.getId());
-            FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flowRule);
-            cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
                 
             //Augment the data to the flow node
 
@@ -466,6 +464,11 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
                         flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
                         sucLogger.debug("Found matching flow in the datastore, augmenting statistics");
                         foundOriginalFlow = true;
+                        // Update entry with timestamp of latest response 
+                        flow.setKey(existingFlow.getKey());
+                        FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
+                        cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
+
                         it.putOperationalData(flowRef, flowBuilder.build());
                         it.commit();
                     }
@@ -490,6 +493,12 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
                             flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
                             sucLogger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
                             foundOriginalFlow = true;
+                            
+                            // Update entry with timestamp of latest response 
+                            flow.setKey(existingFlow.getKey());
+                            FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
+                            cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
+
                             it.putOperationalData(flowRef, flowBuilder.build());
                             it.commit();
                             break;
@@ -498,9 +507,9 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
                 }
             }
             if(!foundOriginalFlow){
-                long flowKey = Long.parseLong(new String("1"+Short.toString(tableId)+"0"+Integer.toString(this.unaccountedFlowsCounter)));
+                String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
                 this.unaccountedFlowsCounter++;
-                FlowKey newFlowKey = new FlowKey(new FlowId(Long.toString(flowKey)));
+                FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
                 InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
                         .augmentation(FlowCapableNode.class)
                         .child(Table.class, new TableKey(tableId))
@@ -508,6 +517,12 @@ public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsList
                 flowBuilder.setKey(newFlowKey);
                 flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
                 sucLogger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",flowBuilder.build());
+                
+                // Update entry with timestamp of latest response 
+                flow.setKey(newFlowKey);
+                FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
+                cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
+
                 it.putOperationalData(flowRef, flowBuilder.build());
                 it.commit();
             }
index 53e14ba..13f8cad 100644 (file)
@@ -67,7 +67,7 @@ public class NetconfOperationServiceImplTest {
         try {
             NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(mockJmxClient("qname1"),
                     mockYangStoreSnapshot("qname2", "qname1"));
-            fail("An exception of type " + IllegalArgumentException.class + " was expected");
+            fail("An exception of type " + IllegalStateException.class + " was expected");
         } catch (IllegalStateException e) {
             String message = e.getMessage();
             Assert.assertThat(
index 889fa84..e319d2c 100644 (file)
@@ -12,7 +12,6 @@ import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
 import org.opendaylight.controller.netconf.api.jmx.DefaultCommitOperationMXBean;
 import org.opendaylight.controller.netconf.api.jmx.NetconfJMXNotification;
-import org.opendaylight.controller.netconf.client.NetconfClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,40 +26,60 @@ import java.io.IOException;
 import java.util.regex.Pattern;
 
 /**
- * Responsible for listening for notifications from netconf containing latest
+ * Responsible for listening for notifications from netconf (via JMX) containing latest
  * committed configuration that should be persisted, and also for loading last
  * configuration.
  */
 @ThreadSafe
-public class ConfigPersisterNotificationHandler implements NotificationListener, Closeable {
+public class ConfigPersisterNotificationHandler implements Closeable {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
     private final MBeanServerConnection mBeanServerConnection;
-    private final NetconfClient netconfClient;
-    private final Persister persisterAggregator;
-    private final Pattern ignoredMissingCapabilityRegex;
+    private final ConfigPersisterNotificationListener listener;
+
 
-    public ConfigPersisterNotificationHandler(MBeanServerConnection mBeanServerConnection, NetconfClient netconfClient,
+    public ConfigPersisterNotificationHandler(MBeanServerConnection mBeanServerConnection,
                                               Persister persisterAggregator, Pattern ignoredMissingCapabilityRegex) {
         this.mBeanServerConnection = mBeanServerConnection;
-        this.netconfClient = netconfClient;
-        this.persisterAggregator = persisterAggregator;
-        this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex;
-    }
+        listener = new ConfigPersisterNotificationListener(persisterAggregator, ignoredMissingCapabilityRegex);
+        registerAsJMXListener(mBeanServerConnection, listener);
 
-    public void init() {
-        registerAsJMXListener();
     }
 
-    private void registerAsJMXListener() {
+    private static void registerAsJMXListener(MBeanServerConnection mBeanServerConnection, ConfigPersisterNotificationListener listener) {
         logger.trace("Called registerAsJMXListener");
         try {
-            mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.objectName, this, null, null);
+            mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.objectName, listener, null, null);
         } catch (InstanceNotFoundException | IOException e) {
             throw new RuntimeException("Cannot register as JMX listener to netconf", e);
         }
     }
 
+    @Override
+    public synchronized void close() {
+        // unregister from JMX
+        ObjectName on = DefaultCommitOperationMXBean.objectName;
+        try {
+            if (mBeanServerConnection.isRegistered(on)) {
+                mBeanServerConnection.removeNotificationListener(on, listener);
+            }
+        } catch (Exception e) {
+            logger.warn("Unable to unregister {} as listener for {}", listener, on, e);
+        }
+    }
+}
+
+class ConfigPersisterNotificationListener implements NotificationListener {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationListener.class);
+
+    private final Persister persisterAggregator;
+    private final Pattern ignoredMissingCapabilityRegex;
+
+    ConfigPersisterNotificationListener(Persister persisterAggregator, Pattern ignoredMissingCapabilityRegex) {
+        this.persisterAggregator = persisterAggregator;
+        this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex;
+    }
+
     @Override
     public void handleNotification(Notification notification, Object handback) {
         if (notification instanceof NetconfJMXNotification == false)
@@ -92,22 +111,4 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
             throw new RuntimeException("Unable to persist configuration snapshot", e);
         }
     }
-
-    @Override
-    public synchronized void close() {
-        // unregister from JMX
-        ObjectName on = DefaultCommitOperationMXBean.objectName;
-        try {
-            if (mBeanServerConnection.isRegistered(on)) {
-                mBeanServerConnection.removeNotificationListener(on, this);
-            }
-        } catch (Exception e) {
-            logger.warn("Unable to unregister {} as listener for {}", this, on, e);
-        }
-    }
-
-    public NetconfClient getNetconfClient() {
-        return netconfClient;
-    }
-
-}
+}
\ No newline at end of file
index 0a844b6..01d872d 100644 (file)
@@ -33,6 +33,7 @@ import java.io.InputStream;
 import java.net.InetSocketAddress;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -44,100 +45,98 @@ public class ConfigPusher {
     private static final int NETCONF_SEND_ATTEMPTS = 20;
 
     private final InetSocketAddress address;
-    private final EventLoopGroup nettyThreadgroup;
+    private final EventLoopGroup nettyThreadGroup;
 
     // Default timeout for netconf becoming stable
-    public static final long DEFAULT_TIMEOUT = TimeUnit.MINUTES.toNanos(2);
+    public static final long DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS = TimeUnit.MINUTES.toMillis(2);
+    public static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000;
     private final int delayMillis = 5000;
-    private final long timeoutNanos;
+    private final long maxWaitForCapabilitiesMillis;
+    private final long connectionTimeoutMillis;
 
-    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadgroup) {
-        this(address, nettyThreadgroup, DEFAULT_TIMEOUT);
+    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup) {
+        this(address, nettyThreadGroup, DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
     }
 
-    @Deprecated
-    public ConfigPusher(InetSocketAddress address, long timeoutMillis, EventLoopGroup nettyThreadgroup) {
-        this(address, nettyThreadgroup, TimeUnit.MILLISECONDS.toNanos(timeoutMillis));
-    }
-
-    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadgroup, long timeoutNanos) {
+    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup,
+                        long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
         this.address = address;
-        this.nettyThreadgroup = nettyThreadgroup;
-        this.timeoutNanos = timeoutNanos;
+        this.nettyThreadGroup = nettyThreadGroup;
+        this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
+        this.connectionTimeoutMillis = connectionTimeoutMillis;
     }
 
-    public synchronized NetconfClient init(List<ConfigSnapshotHolder> configs) throws InterruptedException {
+    public synchronized LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponseWithRetries> pushConfigs(
+            List<ConfigSnapshotHolder> configs) throws InterruptedException {
         logger.debug("Last config snapshots to be pushed to netconf: {}", configs);
-        return pushAllConfigs(configs);
-    }
 
-    private synchronized NetconfClient pushAllConfigs(List<ConfigSnapshotHolder> configs) throws InterruptedException {
         // first just make sure we can connect to netconf, even if nothing is being pushed
-        NetconfClient netconfClient = makeNetconfConnection(Collections.<String>emptySet(), Optional.<NetconfClient>absent());
+        {
+            NetconfClient netconfClient = makeNetconfConnection(Collections.<String>emptySet());
+            Util.closeClientAndDispatcher(netconfClient);
+        }
+        LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponseWithRetries> result = new LinkedHashMap<>();
         // start pushing snapshots:
-        for (ConfigSnapshotHolder configSnapshotHolder: configs){
-            netconfClient = pushSnapshotWithRetries(configSnapshotHolder, Optional.of(netconfClient));
-            logger.debug("Config snapshot pushed successfully: {}", configSnapshotHolder);
+        for (ConfigSnapshotHolder configSnapshotHolder : configs) {
+            EditAndCommitResponseWithRetries editAndCommitResponseWithRetries = pushSnapshotWithRetries(configSnapshotHolder);
+            logger.debug("Config snapshot pushed successfully: {}, result: {}", configSnapshotHolder, result);
+            result.put(configSnapshotHolder, editAndCommitResponseWithRetries);
         }
-
         logger.debug("All configuration snapshots have been pushed successfully.");
-        return netconfClient;
+        return result;
     }
 
-    private synchronized NetconfClient pushSnapshotWithRetries(ConfigSnapshotHolder configSnapshotHolder,
-                                                               Optional<NetconfClient> oldClientForPossibleReuse)
+    /**
+     * Checks for ConflictingVersionException and retries until optimistic lock succeeds or maximal
+     * number of attempts is reached.
+     */
+    private synchronized EditAndCommitResponseWithRetries pushSnapshotWithRetries(ConfigSnapshotHolder configSnapshotHolder)
             throws InterruptedException {
 
-        Exception lastException = null;
+        ConflictingVersionException lastException = null;
         int maxAttempts = 30;
-        for(int i = 0 ; i < maxAttempts; i++) {
-            NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities(), oldClientForPossibleReuse);
+
+        for (int retryAttempt = 1; retryAttempt <= maxAttempts; retryAttempt++) {
+            NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities());
             logger.trace("Pushing following xml to netconf {}", configSnapshotHolder);
             try {
-                pushLastConfig(configSnapshotHolder, netconfClient);
-                return netconfClient;
-            } catch (ConflictingVersionException | IOException e) {
-                Util.closeClientAndDispatcher(netconfClient);
+                EditAndCommitResponse editAndCommitResponse = pushLastConfig(configSnapshotHolder, netconfClient);
+                return new EditAndCommitResponseWithRetries(editAndCommitResponse, retryAttempt);
+            } catch (ConflictingVersionException e) {
                 lastException = e;
                 Thread.sleep(1000);
-            } catch (SAXException e) {
-                throw new IllegalStateException("Unable to load last config", e);
+            } catch (RuntimeException e) {
+                throw new IllegalStateException("Unable to load " + configSnapshotHolder, e);
+            } finally {
+                Util.closeClientAndDispatcher(netconfClient);
             }
         }
-        throw new IllegalStateException("Failed to push configuration, maximum attempt count has been reached: "
-                + maxAttempts, lastException);
+        throw new IllegalStateException("Maximum attempt count has been reached for pushing " + configSnapshotHolder,
+                lastException);
     }
 
     /**
      * @param expectedCaps capabilities that server hello must contain. Will retry until all are found or throws RuntimeException.
      *                     If empty set is provided, will only make sure netconf client successfuly connected to the server.
-     * @param maybeOldClient if present, close it.
      * @return NetconfClient that has all required capabilities from server.
      */
-    private synchronized NetconfClient makeNetconfConnection(Set<String> expectedCaps,
-                                                             Optional<NetconfClient> maybeOldClient)
-            throws InterruptedException {
-
-        if (maybeOldClient.isPresent()) {
-            NetconfClient oldClient = maybeOldClient.get();
-            Util.closeClientAndDispatcher(oldClient);
-        }
+    private synchronized NetconfClient makeNetconfConnection(Set<String> expectedCaps) throws InterruptedException {
 
         // TODO think about moving capability subset check to netconf client
         // could be utilized by integration tests
 
-        final long pollingStart = System.nanoTime();
-        final long deadline = pollingStart + timeoutNanos;
+        final long pollingStartNanos = System.nanoTime();
+        final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis);
         int attempt = 0;
 
         String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(),
                 Integer.toString(address.getPort()), "tcp", Optional.of("persister"));
 
-        Set<String> latestCapabilities = new HashSet<>();
-        while (System.nanoTime() < deadline) {
+        Set<String> latestCapabilities = null;
+        while (System.nanoTime() < deadlineNanos) {
             attempt++;
-            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup,
-                    nettyThreadgroup, additionalHeader);
+            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadGroup,
+                    nettyThreadGroup, additionalHeader, connectionTimeoutMillis);
             NetconfClient netconfClient;
             try {
                 netconfClient = new NetconfClient(this.toString(), address, delayMillis, netconfClientDispatcher);
@@ -157,6 +156,10 @@ public class ConfigPusher {
             Util.closeClientAndDispatcher(netconfClient);
             Thread.sleep(delayMillis);
         }
+        if (latestCapabilities == null) {
+            logger.error("Could not connect to the server in {} ms", maxWaitForCapabilitiesMillis);
+            throw new RuntimeException("Could not connect to netconf server");
+        }
         Set<String> allNotFound = new HashSet<>(expectedCaps);
         allNotFound.removeAll(latestCapabilities);
         logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
@@ -165,70 +168,152 @@ public class ConfigPusher {
     }
 
 
-    private synchronized void pushLastConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfClient netconfClient)
-            throws ConflictingVersionException, IOException, SAXException {
+    /**
+     * Sends two RPCs to the netconf server: edit-config and commit.
+     *
+     * @param configSnapshotHolder
+     * @param netconfClient
+     * @throws ConflictingVersionException if commit fails on optimistic lock failure inside of config-manager
+     * @throws java.lang.RuntimeException  if edit-config or commit fails otherwise
+     */
+    private synchronized EditAndCommitResponse pushLastConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfClient netconfClient)
+            throws ConflictingVersionException {
 
-        Element xmlToBePersisted = XmlUtil.readXmlToElement(configSnapshotHolder.getConfigSnapshot());
+        Element xmlToBePersisted;
+        try {
+            xmlToBePersisted = XmlUtil.readXmlToElement(configSnapshotHolder.getConfigSnapshot());
+        } catch (SAXException | IOException e) {
+            throw new IllegalStateException("Cannot parse " + configSnapshotHolder);
+        }
         logger.trace("Pushing last configuration to netconf: {}", configSnapshotHolder);
-        StringBuilder response = new StringBuilder("editConfig response = {");
 
-        NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
+        NetconfMessage editConfigMessage = createEditConfigMessage(xmlToBePersisted);
 
         // sending message to netconf
-        NetconfMessage responseMessage = getResponse(message, netconfClient);
-
-        NetconfUtil.checkIsMessageOk(responseMessage);
-        response.append(XmlUtil.toString(responseMessage.getDocument()));
-        response.append("}");
-        responseMessage = getResponse(getNetconfMessageFromResource("/netconfOp/commit.xml"), netconfClient);
-
+        NetconfMessage editResponseMessage;
+        try {
+            editResponseMessage = sendRequestGetResponseCheckIsOK(editConfigMessage, netconfClient);
+        } catch (IOException e) {
+            throw new IllegalStateException("Edit-config failed on " + configSnapshotHolder, e);
+        }
 
+        // commit
+        NetconfMessage commitResponseMessage;
+        try {
+            commitResponseMessage = sendRequestGetResponseCheckIsOK(getCommitMessage(), netconfClient);
+        } catch (IOException e) {
+            throw new IllegalStateException("Edit commit succeeded, but commit failed on " + configSnapshotHolder, e);
+        }
 
-        NetconfUtil.checkIsMessageOk(responseMessage);
-        response.append("commit response = {");
-        response.append(XmlUtil.toString(responseMessage.getDocument()));
-        response.append("}");
-        logger.trace("Last configuration loaded successfully");
-        logger.trace("Detailed message {}", response);
+        if (logger.isTraceEnabled()) {
+            StringBuilder response = new StringBuilder("editConfig response = {");
+            response.append(XmlUtil.toString(editResponseMessage.getDocument()));
+            response.append("}");
+            response.append("commit response = {");
+            response.append(XmlUtil.toString(commitResponseMessage.getDocument()));
+            response.append("}");
+            logger.trace("Last configuration loaded successfully");
+            logger.trace("Detailed message {}", response);
+        }
+        return new EditAndCommitResponse(editResponseMessage, commitResponseMessage);
     }
 
-    private static NetconfMessage getResponse(NetconfMessage request, NetconfClient netconfClient) throws IOException {
+
+    private static NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient) throws IOException {
         try {
-            return netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
-        } catch (RuntimeException e) {
+            NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+            NetconfUtil.checkIsMessageOk(netconfMessage);
+            return netconfMessage;
+        } catch (RuntimeException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
             logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e);
             throw new IOException("Failed to execute netconf transaction", e);
         }
     }
 
-    private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) throws IOException, SAXException {
-        try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
-            Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
+
+    // load editConfig.xml template, populate /rpc/edit-config/config with parameter
+    private static NetconfMessage createEditConfigMessage(Element dataElement) {
+        String editConfigResourcePath = "/netconfOp/editConfig.xml";
+        try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcePath)) {
+            Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcePath);
 
             Document doc = XmlUtil.readXmlToDocument(stream);
 
-            doc.getDocumentElement();
             XmlElement editConfigElement = XmlElement.fromDomDocument(doc).getOnlyChildElement();
             XmlElement configWrapper = editConfigElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
             editConfigElement.getDomElement().removeChild(configWrapper.getDomElement());
             for (XmlElement el : XmlElement.fromDomElement(dataElement).getChildElements()) {
-                configWrapper.appendChild((Element) doc.importNode(el.getDomElement(), true));
+                boolean deep = true;
+                configWrapper.appendChild((Element) doc.importNode(el.getDomElement(), deep));
             }
             editConfigElement.appendChild(configWrapper.getDomElement());
             return new NetconfMessage(doc);
         } catch (IOException | SAXException e) {
-            logger.debug("Failed to create edit-config message for resource {}", editConfigResourcename, e);
-            throw e;
+            // error reading the xml file bundled into the jar
+            throw new RuntimeException("Error while opening local resource " + editConfigResourcePath, e);
         }
     }
 
-    private static NetconfMessage getNetconfMessageFromResource(String resource) throws IOException, SAXException {
+    private static NetconfMessage getCommitMessage() {
+        String resource = "/netconfOp/commit.xml";
         try (InputStream stream = ConfigPusher.class.getResourceAsStream(resource)) {
             Preconditions.checkNotNull(stream, "Unable to load resource " + resource);
             return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
         } catch (SAXException | IOException e) {
-            logger.debug("Failed to parse netconf message for resource {}", resource, e);
-            throw e;
+            // error reading the xml file bundled into the jar
+            throw new RuntimeException("Error while opening local resource " + resource, e);
+        }
+    }
+
+    static class EditAndCommitResponse {
+        private final NetconfMessage editResponse, commitResponse;
+
+        EditAndCommitResponse(NetconfMessage editResponse, NetconfMessage commitResponse) {
+            this.editResponse = editResponse;
+            this.commitResponse = commitResponse;
+        }
+
+        public NetconfMessage getEditResponse() {
+            return editResponse;
+        }
+
+        public NetconfMessage getCommitResponse() {
+            return commitResponse;
+        }
+
+        @Override
+        public String toString() {
+            return "EditAndCommitResponse{" +
+                    "editResponse=" + editResponse +
+                    ", commitResponse=" + commitResponse +
+                    '}';
+        }
+    }
+
+
+    static class EditAndCommitResponseWithRetries {
+        private final EditAndCommitResponse editAndCommitResponse;
+        private final int retries;
+
+        EditAndCommitResponseWithRetries(EditAndCommitResponse editAndCommitResponse, int retries) {
+            this.editAndCommitResponse = editAndCommitResponse;
+            this.retries = retries;
+        }
+
+        public int getRetries() {
+            return retries;
+        }
+
+        public EditAndCommitResponse getEditAndCommitResponse() {
+            return editAndCommitResponse;
+        }
+
+        @Override
+        public String toString() {
+            return "EditAndCommitResponseWithRetries{" +
+                    "editAndCommitResponse=" + editAndCommitResponse +
+                    ", retries=" + retries +
+                    '}';
         }
     }
-}
+}
\ No newline at end of file
index 179c968..1157ddb 100644 (file)
@@ -10,11 +10,9 @@ package org.opendaylight.controller.netconf.persist.impl.osgi;
 
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
-import org.opendaylight.controller.netconf.client.NetconfClient;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
 import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
-import org.opendaylight.controller.netconf.persist.impl.Util;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -25,7 +23,6 @@ import javax.management.MBeanServer;
 import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
 import java.util.regex.Pattern;
-import java.util.concurrent.TimeUnit;
 
 public class ConfigPersisterActivator implements BundleActivator {
 
@@ -34,7 +31,7 @@ public class ConfigPersisterActivator implements BundleActivator {
     private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
     private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
 
-    private static final String PUSH_TIMEOUT = "pushTimeout";
+    private static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
 
     public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
 
@@ -44,9 +41,8 @@ public class ConfigPersisterActivator implements BundleActivator {
 
 
     private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
-    private volatile NetconfClient netconfClient;
     private Thread initializationThread;
-    private EventLoopGroup nettyThreadgroup;
+    private EventLoopGroup nettyThreadGroup;
     private PersisterAggregator persisterAggregator;
 
     @Override
@@ -63,15 +59,22 @@ public class ConfigPersisterActivator implements BundleActivator {
             regex = DEFAULT_IGNORED_REGEX;
         }
 
-        String timeoutProperty = propertiesProvider.getProperty(PUSH_TIMEOUT);
-        long timeout = timeoutProperty == null ? ConfigPusher.DEFAULT_TIMEOUT : TimeUnit.SECONDS.toNanos(Integer.valueOf(timeoutProperty));
+        String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
+        long maxWaitForCapabilitiesMillis;
+        if (timeoutProperty == null) {
+            maxWaitForCapabilitiesMillis = ConfigPusher.DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS;
+        } else {
+            maxWaitForCapabilitiesMillis = Integer.valueOf(timeoutProperty);
+        }
 
         final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
-        nettyThreadgroup = new NioEventLoopGroup();
+        nettyThreadGroup = new NioEventLoopGroup();
 
         persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
-        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context, "Netconf is not configured, persister is not operational", true);
-        final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadgroup);
+        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
+                "Netconf is not configured, persister is not operational", true);
+        final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadGroup, maxWaitForCapabilitiesMillis,
+                ConfigPusher.DEFAULT_CONNECTION_TIMEOUT_MILLIS);
 
 
         // offload initialization to another thread in order to stop blocking activator
@@ -79,11 +82,9 @@ public class ConfigPersisterActivator implements BundleActivator {
             @Override
             public void run() {
                 try {
-                    netconfClient = configPusher.init(persisterAggregator.loadLastConfigs());
-                    jmxNotificationHandler = new ConfigPersisterNotificationHandler(
-                            platformMBeanServer, netconfClient, persisterAggregator,
+                    configPusher.pushConfigs(persisterAggregator.loadLastConfigs());
+                    jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator,
                             ignoredMissingCapabilityRegex);
-                    jmxNotificationHandler.init();
                 } catch (InterruptedException e) {
                     Thread.currentThread().interrupt();
                     logger.error("Interrupted while waiting for netconf connection");
@@ -103,15 +104,7 @@ public class ConfigPersisterActivator implements BundleActivator {
         if (jmxNotificationHandler != null) {
             jmxNotificationHandler.close();
         }
-        if (netconfClient != null) {
-            netconfClient = jmxNotificationHandler.getNetconfClient();
-            try {
-                Util.closeClientAndDispatcher(netconfClient);
-            } catch (Exception e) {
-                logger.warn("Unable to close connection to netconf {}", netconfClient, e);
-            }
-        }
-        nettyThreadgroup.shutdownGracefully();
+        nettyThreadGroup.shutdownGracefully();
         persisterAggregator.close();
     }
 }
index 37db39f..c6111ab 100644 (file)
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>generate-sources</goal>
-                        </goals>
-                        <configuration>
-                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
-                            <codeGenerators>
-                                <generator>
-                                    <codeGeneratorClass>
-                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
-                                    </codeGeneratorClass>
-                                    <outputBaseDir>
-                                        ${project.build.directory}/generated-sources/monitoring
-                                    </outputBaseDir>
-                                </generator>
-                            </codeGenerators>
-                            <inspectDependencies>true</inspectDependencies>
-                        </configuration>
-                    </execution>
-                </executions>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.opendaylight.yangtools</groupId>
-                        <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>${yangtools.version}</version>
-                    </dependency>
-                </dependencies>
             </plugin>
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>build-helper-maven-plugin</artifactId>
-                <version>1.7</version>
-                <executions>
-                    <execution>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>${project.build.directory}/generated-sources/monitoring</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
             </plugin>
 
             <plugin>
index a068edf..e6a186c 100644 (file)
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>generate-sources</goal>
-                        </goals>
-                        <configuration>
-                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
-                            <codeGenerators>
-                                <generator>
-                                    <codeGeneratorClass>
-                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
-                                    </codeGeneratorClass>
-                                    <outputBaseDir>
-                                        ${project.build.directory}/generated-sources/monitoring
-                                    </outputBaseDir>
-                                </generator>
-                            </codeGenerators>
-                            <inspectDependencies>true</inspectDependencies>
-                        </configuration>
-                    </execution>
-                </executions>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.opendaylight.yangtools</groupId>
-                        <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>${yangtools.version}</version>
-                    </dependency>
-                </dependencies>
             </plugin>
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>build-helper-maven-plugin</artifactId>
-                <version>1.7</version>
-                <executions>
-                    <execution>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>${project.build.directory}/generated-sources/monitoring</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
             </plugin>
 
             <plugin>
index 67d95bb..4fcad2c 100644 (file)
@@ -8,16 +8,11 @@
 
 package org.opendaylight.controller.netconf.client;
 
+import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Sets;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
@@ -25,8 +20,13 @@ import org.opendaylight.protocol.framework.TimedReconnectStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 public class NetconfClient implements Closeable {
 
@@ -103,7 +103,7 @@ public class NetconfClient implements Closeable {
     }
 
     public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
-        long startTime = System.currentTimeMillis();
+        Stopwatch stopwatch = new Stopwatch().start();
         Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
         //logger.debug("Sending message: {}",XmlUtil.toString(message.getDocument()));
         clientSession.sendMessage(message);
@@ -115,8 +115,8 @@ public class NetconfClient implements Closeable {
         } catch (IllegalStateException e) {
             throw new IllegalStateException(this + " Cannot read message from " + address, e);
         } finally {
-            long diffMillis = System.currentTimeMillis() - startTime;
-            logger.debug("Total time spent waiting for response {}", diffMillis);
+            stopwatch.stop();
+            logger.debug("Total time spent waiting for response {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
         }
     }
 
index fc6f87d..1228a84 100644 (file)
@@ -8,15 +8,12 @@
 
 package org.opendaylight.controller.netconf.client;
 
+import com.google.common.base.Optional;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
-
-import java.io.Closeable;
-import java.net.InetSocketAddress;
-
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
@@ -28,7 +25,8 @@ import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
+import java.io.Closeable;
+import java.net.InetSocketAddress;
 
 public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
 
@@ -37,16 +35,16 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
     private final NetconfClientSessionNegotiatorFactory negotatorFactory;
     private final HashedWheelTimer timer;
 
-    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
+    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, long clientConnectionTimeoutMillis) {
         super(bossGroup, workerGroup);
         timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent(), clientConnectionTimeoutMillis);
     }
 
-    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader) {
+    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader, long connectionTimeoutMillis) {
         super(bossGroup, workerGroup);
         timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), connectionTimeoutMillis);
     }
 
     public Future<NetconfClientSession> createClient(InetSocketAddress address,
index dd8e3c9..100b98c 100644 (file)
@@ -34,8 +34,9 @@ public class NetconfClientSessionNegotiator extends
         AbstractNetconfSessionNegotiator<NetconfSessionPreferences, NetconfClientSession> {
 
     protected NetconfClientSessionNegotiator(NetconfSessionPreferences sessionPreferences,
-            Promise<NetconfClientSession> promise, Channel channel, Timer timer, SessionListener sessionListener) {
-        super(sessionPreferences, promise, channel, timer, sessionListener);
+            Promise<NetconfClientSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+            long connectionTimeoutMillis) {
+        super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
 
     private static Collection<String> getCapabilities(Document doc) {
index abfbdd5..db6c024 100644 (file)
@@ -8,13 +8,11 @@
 
 package org.opendaylight.controller.netconf.client;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
-
-import java.io.IOException;
-import java.io.InputStream;
-
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -23,18 +21,20 @@ import org.opendaylight.protocol.framework.SessionNegotiator;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
 import org.xml.sax.SAXException;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.io.InputStream;
 
 public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory {
 
     private final Timer timer;
 
     private final Optional<String> additionalHeader;
+    private final long connectionTimeoutMillis;
 
-    public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader) {
+    public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader, long connectionTimeoutMillis) {
         this.timer = timer;
         this.additionalHeader = additionalHeader;
+        this.connectionTimeoutMillis = connectionTimeoutMillis;
     }
 
     private static NetconfMessage loadHelloMessageTemplate() {
@@ -57,7 +57,7 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF
         }
         NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage);
         return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
-                sessionListenerFactory.getSessionListener());
+                sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
     }
 
 }
index ee07b39..06239b2 100644 (file)
@@ -8,16 +8,13 @@
 
 package org.opendaylight.controller.netconf.client;
 
+import com.google.common.base.Optional;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
@@ -33,7 +30,8 @@ import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.SessionListener;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 
-import com.google.common.base.Optional;
+import java.io.IOException;
+import java.net.InetSocketAddress;
 
 public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
 
@@ -42,19 +40,19 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
     private NetconfClientSessionNegotiatorFactory negotatorFactory;
 
     public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
-            EventLoopGroup workerGroup) {
-        super(bossGroup, workerGroup);
+            EventLoopGroup workerGroup, long connectionTimeoutMillis) {
+        super(bossGroup, workerGroup, connectionTimeoutMillis);
         this.authHandler = authHandler;
         this.timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent());
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent(), connectionTimeoutMillis);
     }
 
     public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
-            EventLoopGroup workerGroup, String additionalHeader) {
-        super(bossGroup, workerGroup, additionalHeader);
+            EventLoopGroup workerGroup, String additionalHeader, long socketTimeoutMillis) {
+        super(bossGroup, workerGroup, additionalHeader, socketTimeoutMillis);
         this.authHandler = authHandler;
         this.timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader));
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), socketTimeoutMillis);
     }
 
     public Future<NetconfClientSession> createClient(InetSocketAddress address,
index 7f1d289..a3cc104 100644 (file)
@@ -29,7 +29,7 @@ public class SSHNetconfClientLiveTest {
         nettyThreadgroup = new NioEventLoopGroup();
         netconfClientDispatcher = new NetconfSshClientDispatcher(new LoginPassword(
                 System.getProperty("username"), System.getProperty("password")),
-                nettyThreadgroup, nettyThreadgroup);
+                nettyThreadgroup, nettyThreadgroup, 5000);
     }
 
     @Test
index 8ba4cdc..9155586 100644 (file)
@@ -8,12 +8,10 @@
 
 package org.opendaylight.controller.netconf.impl;
 
+import com.google.common.base.Optional;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
-
-import java.net.InetSocketAddress;
-
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
 import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
@@ -22,7 +20,7 @@ import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
+import java.net.InetSocketAddress;
 
 public class NetconfServerSessionNegotiator extends
         AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession> {
@@ -30,8 +28,9 @@ public class NetconfServerSessionNegotiator extends
     static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
 
     protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
-            Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener) {
-        super(sessionPreferences, promise, channel, timer, sessionListener);
+            Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+            long connectionTimeoutMillis) {
+        super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
 
     @Override
index 3c14d51..98462b8 100644 (file)
@@ -40,12 +40,14 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     private static final Document helloMessageTemplate = loadHelloMessageTemplate();
     private final SessionIdProvider idProvider;
     private final NetconfOperationServiceFactoryListener factoriesListener;
+    private final long connectionTimeoutMillis;
 
     public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationServiceFactoryListener factoriesListener,
-            SessionIdProvider idProvider) {
+            SessionIdProvider idProvider, long connectionTimeoutMillis) {
         this.timer = timer;
         this.factoriesListener = factoriesListener;
         this.idProvider = idProvider;
+        this.connectionTimeoutMillis = connectionTimeoutMillis;
     }
 
     private static Document loadHelloMessageTemplate() {
@@ -64,7 +66,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
         NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId),
                 sessionId);
         return new NetconfServerSessionNegotiator(proposal, promise, channel, timer,
-                sessionListenerFactory.getSessionListener());
+                sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
     }
 
     private static final XPathExpression sessionIdXPath = XMLNetconfUtil
index abebacf..95f7353 100644 (file)
@@ -48,8 +48,9 @@ public class NetconfImplActivator implements BundleActivator {
 
         SessionIdProvider idProvider = new SessionIdProvider();
         timer = new HashedWheelTimer();
+        long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                timer, factoriesListener, idProvider);
+                timer, factoriesListener, idProvider, connectionTimeoutMillis);
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
index 958ac42..0ef2c28 100644 (file)
@@ -8,34 +8,14 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
-
-import java.io.DataOutputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import javax.management.ObjectName;
-
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -63,15 +43,30 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import javax.management.ObjectName;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 public class ConcurrentClientsTest {
 
     private static final int CONCURRENCY = 16;
-    private static EventLoopGroup nettyGroup = new NioEventLoopGroup();
-    public static final NetconfClientDispatcher NETCONF_CLIENT_DISPATCHER =
-            new NetconfClientDispatcher( nettyGroup, nettyGroup);
+    private EventLoopGroup nettyGroup;
+    private NetconfClientDispatcher netconfClientDispatcher;
 
     @Mock
     private YangStoreService yangStoreService;
@@ -88,6 +83,8 @@ public class ConcurrentClientsTest {
     @Mock
     private SessionMonitoringService monitoring;
 
+    HashedWheelTimer hashedWheelTimer;
+
     @Before
     public void setUp() throws Exception {
         { // init mocks
@@ -102,12 +99,16 @@ public class ConcurrentClientsTest {
             doReturn(Collections.emptySet()).when(jmxClient).lookupConfigBeans();
         }
 
+        nettyGroup = new NioEventLoopGroup();
+        netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, 5000);
+
         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
         factoriesListener.onAddNetconfOperationServiceFactory(mockOpF());
 
         SessionIdProvider idProvider = new SessionIdProvider();
+        hashedWheelTimer = new HashedWheelTimer();
         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
+                hashedWheelTimer, factoriesListener, idProvider, 5000);
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
@@ -123,8 +124,9 @@ public class ConcurrentClientsTest {
         s.await();
     }
 
-    @AfterClass
-    public static void tearDownStatic() {
+    @After
+    public void tearDown(){
+        hashedWheelTimer.stop();
         nettyGroup.shutdownGracefully();
     }
 
@@ -285,7 +287,7 @@ public class ConcurrentClientsTest {
         @Override
         public void run() {
             try {
-                final NetconfClient netconfClient = new NetconfClient(clientId, netconfAddress, NETCONF_CLIENT_DISPATCHER);
+                final NetconfClient netconfClient = new NetconfClient(clientId, netconfAddress, netconfClientDispatcher);
                 long sessionId = netconfClient.getSessionId();
                 logger.info("Client with sessionid {} hello exchanged", sessionId);
 
index 0ecc1cb..9835c23 100644 (file)
@@ -26,6 +26,7 @@ public class NetconfDispatcherImplTest {
     private EventLoopGroup nettyGroup;
     private NetconfServerDispatcher dispatch;
     private DefaultCommitNotificationProducer commitNot;
+    private HashedWheelTimer hashedWheelTimer;
 
     @Before
     public void setUp() throws Exception {
@@ -36,8 +37,9 @@ public class NetconfDispatcherImplTest {
         NetconfOperationServiceFactoryListener factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
 
         SessionIdProvider idProvider = new SessionIdProvider();
+        hashedWheelTimer = new HashedWheelTimer();
         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                new HashedWheelTimer(), factoriesListener, idProvider);
+                hashedWheelTimer, factoriesListener, idProvider, 5000);
 
         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
                 factoriesListener, commitNot, idProvider, null);
@@ -49,6 +51,7 @@ public class NetconfDispatcherImplTest {
 
     @After
     public void tearDown() throws Exception {
+        hashedWheelTimer.stop();
         commitNot.close();
         nettyGroup.shutdownGracefully();
     }
diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java
new file mode 100644 (file)
index 0000000..b261218
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 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.it;
+
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import org.junit.After;
+import org.junit.Before;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
+import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
+import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+
+public class AbstractNetconfConfigTest extends AbstractConfigTest {
+
+    protected EventLoopGroup nettyThreadgroup;
+    private HashedWheelTimer hashedWheelTimer;
+
+    @Before
+    public void setUpAbstractNetconfConfigTest() {
+        nettyThreadgroup = new NioEventLoopGroup();
+        hashedWheelTimer = new HashedWheelTimer();
+    }
+
+
+    protected NetconfServerDispatcher createDispatcher(
+            NetconfOperationServiceFactoryListenerImpl factoriesListener, SessionMonitoringService sessionMonitoringService,
+            DefaultCommitNotificationProducer commitNotifier) {
+        SessionIdProvider idProvider = new SessionIdProvider();
+
+        NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
+                hashedWheelTimer, factoriesListener, idProvider, 5000);
+
+        NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
+                factoriesListener, commitNotifier, idProvider,
+                sessionMonitoringService);
+
+        NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
+                serverNegotiatorFactory, listenerFactory);
+        return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
+    }
+
+
+    @After
+    public void cleanUpTimer() {
+        hashedWheelTimer.stop();
+        nettyThreadgroup.shutdownGracefully();
+    }
+
+}
index 14f70d3..0037981 100644 (file)
@@ -10,17 +10,14 @@ package org.opendaylight.controller.netconf.it;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import io.netty.channel.ChannelFuture;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.HashedWheelTimer;
 import org.apache.commons.lang3.StringUtils;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
-import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 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;
@@ -35,9 +32,6 @@ import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
-import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
-import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
-import org.opendaylight.controller.netconf.impl.SessionIdProvider;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
@@ -63,7 +57,6 @@ import java.net.InetSocketAddress;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 
 import static junit.framework.Assert.assertEquals;
@@ -74,16 +67,18 @@ import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
-public class NetconfConfigPersisterITTest extends AbstractConfigTest {
+public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
 
     private static final Logger logger =  LoggerFactory.getLogger(NetconfConfigPersisterITTest.class);
 
     private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
 
-    private EventLoopGroup nettyThreadgroup;
+
 
     private NetconfClientDispatcher clientDispatcher;
 
+    DefaultCommitNotificationProducer commitNotifier;
+
     @Before
     public void setUp() throws Exception {
         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(NetconfITTest.getModuleFactoriesS().toArray(
@@ -97,13 +92,18 @@ public class NetconfConfigPersisterITTest extends AbstractConfigTest {
                 .onAddNetconfOperationServiceFactory(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
                         new NetconfMonitoringOperationService(monitoringService)));
 
-        nettyThreadgroup = new NioEventLoopGroup();
 
-        NetconfServerDispatcher dispatch = createDispatcher(factoriesListener);
+        commitNotifier = new DefaultCommitNotificationProducer(platformMBeanServer);
+        NetconfServerDispatcher dispatch = createDispatcher(factoriesListener, mockSessionMonitoringService(), commitNotifier);
         ChannelFuture s = dispatch.createServer(tcpAddress);
         s.await();
 
-        clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+        clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
+    }
+
+    @After
+    public void cleanUp(){
+        commitNotifier.close();
     }
 
     private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
@@ -111,27 +111,16 @@ public class NetconfConfigPersisterITTest extends AbstractConfigTest {
         return new HardcodedYangStoreService(yangDependencies);
     }
 
-    private NetconfServerDispatcher createDispatcher(
-                                                     NetconfOperationServiceFactoryListenerImpl factoriesListener) {
-        SessionIdProvider idProvider = new SessionIdProvider();
-        NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
-
-        NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
-                factoriesListener, new DefaultCommitNotificationProducer(platformMBeanServer), idProvider, mockSessionMonitoringService());
-
-        NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
-                serverNegotiatorFactory, listenerFactory);
-        return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
-    }
 
-    private SessionMonitoringService mockSessionMonitoringService() {
+    protected SessionMonitoringService mockSessionMonitoringService() {
         SessionMonitoringService mockedSessionMonitor = mock(Sessio