Merge "Added transactions statistics for BI Broker."
authorEd Warnicke <eaw@cisco.com>
Sat, 7 Dec 2013 23:03:29 +0000 (23:03 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 7 Dec 2013 23:03:29 +0000 (23:03 +0000)
120 files changed:
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolder.java
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolderImpl.java [new file with mode: 0644]
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/Persister.java
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java
opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedCapabilities.txt [moved from opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedCapabilities.txt with 100% similarity]
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedSnapshot.xml [moved from opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedSnapshot.xml with 100% similarity]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml [new file with mode: 0644]
opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java
opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/FtlFilePersister.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/ModuleField.java
opendaylight/config/yang-jmx-generator-plugin/src/main/resources/freeMarker/module_abs_template_new.ftl
opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Dependency.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/DependencyAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListDependenciesAttribute.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryTest.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/SchemaContextTest.java
opendaylight/config/yang-jmx-generator/src/test/resources/test-config-threads-java.yang
opendaylight/config/yang-test/src/main/yang/config-test-impl.yang
opendaylight/distribution/opendaylight/pom.xml
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java
opendaylight/md-sal/model/model-flow-base/src/main/yang/match-types.yang
opendaylight/md-sal/sal-binding-it/pom.xml
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectXmlReader.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/mapping/ObjectMapper.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/resolving/ObjectResolver.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectXmlWriter.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImpl.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.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 [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/NoOpStorageAdapter.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/config-persister-impl/src/main/resources/netconfOp/client_hello.xml
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandlerTest.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/DummyAdapter.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
opendaylight/netconf/ietf-netconf-monitoring/pom.xml [new file with mode: 0644]
opendaylight/netconf/ietf-netconf-monitoring/src/main/yang/ietf-netconf-monitoring.yang [new file with mode: 0644]
opendaylight/netconf/netconf-api/pom.xml
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/NetconfManagementSession.java [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/NetconfMonitoringService.java [new file with mode: 0644]
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/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-impl/pom.xml
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListenerFactory.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/mapping/operations/DefaultCloseSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStartExi.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExi.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTracker.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/SessionMonitoringService.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/DeserializerExceptionHandler.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java [new file with mode: 0644]
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/pom.xml
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 [new file with mode: 0644]
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/Capability.java
opendaylight/netconf/netconf-monitoring/pom.xml [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/Get.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationService.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTracker.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializer.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSchema.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/NetconfState.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java [new file with mode: 0644]
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/messages/NetconfMessageFactory.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtil.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlNetconfConstants.java
opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/client_hello_with_auth.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig_none.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_differentNamespaceTO.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/namespaces/editConfig_typeNameConfigAttributeMatching.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised2.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised3.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised4.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised5.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised6.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised7.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unrecognised/editConfig_unrecognised8.xml
opendaylight/netconf/pom.xml

index 654326a898cc735c9d0cf69529cbfc992d1069b3..37d29d746e41f82ba63a940976e373b523e5f275 100644 (file)
@@ -4,14 +4,15 @@ import java.util.SortedSet;
 
 public interface ConfigSnapshotHolder {
 
-        /**
-         * Get part of get-config document that contains just
-         */
-        String getConfigSnapshot();
+    /**
+     * Get part of get-config document that contains just
+     */
+    String getConfigSnapshot();
 
 
-        /**
-         * Get only required capabilities referenced by the snapshot.
-         */
-        SortedSet<String> getCapabilities();
-    }
+    /**
+     * Get only required capabilities referenced by the snapshot.
+     */
+    SortedSet<String> getCapabilities();
+
+}
diff --git a/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolderImpl.java b/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolderImpl.java
new file mode 100644 (file)
index 0000000..a0586df
--- /dev/null
@@ -0,0 +1,39 @@
+package org.opendaylight.controller.config.persist.api;
+
+import java.util.SortedSet;
+
+public class ConfigSnapshotHolderImpl implements ConfigSnapshotHolder {
+
+    private final String snapshot;
+    private final SortedSet<String> caps;
+    private final String fileName;
+
+    public ConfigSnapshotHolderImpl(String configSnapshot, SortedSet<String> capabilities, String fileName) {
+        this.snapshot = configSnapshot;
+        this.caps = capabilities;
+        this.fileName = fileName;
+    }
+
+    @Override
+    public String getConfigSnapshot() {
+        return snapshot;
+    }
+
+    @Override
+    public SortedSet<String> getCapabilities() {
+        return caps;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    @Override
+    public String toString() {
+        return "ConfigSnapshotHolderImpl{" +
+                "snapshot='" + snapshot + '\'' +
+                ", caps=" + caps +
+                ", fileName='" + fileName + '\'' +
+                '}';
+    }
+}
index 1448e553e3017a478ee57a8e833b0ee3a9a63577..5509c9943745a2cc658b0c29a3bfc90797300da8 100644 (file)
@@ -8,9 +8,8 @@
 
 package org.opendaylight.controller.config.persist.api;
 
-import com.google.common.base.Optional;
-
 import java.io.IOException;
+import java.util.List;
 
 /**
  * Base interface for persister implementation.
@@ -19,7 +18,7 @@ public interface Persister extends AutoCloseable {
 
     void persistConfig(ConfigSnapshotHolder configSnapshotHolder) throws IOException;
 
-    Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException;
+    List<ConfigSnapshotHolder> loadLastConfigs() throws IOException;
 
     @Override
     void close();
index 25628b6041de94cc099eef49314756b77171324d..39595edb0b728de43917e32d9d7a71283499f293 100644 (file)
@@ -8,10 +8,10 @@
 package org.opendaylight.controller.config.persist.storage.directory;
 
 import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
 import com.google.common.io.Files;
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -64,30 +64,25 @@ public class DirectoryPersister implements Persister {
     }
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         File[] filesArray = storage.listFiles();
-        if (filesArray.length == 0) {
-            return Optional.absent();
+        if (filesArray == null || filesArray.length == 0) {
+            return Collections.emptyList();
         }
         List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
         Collections.sort(sortedFiles);
         // combine all found files
+        logger.debug("Reading files in following order: {}", sortedFiles);
 
-        SortedSet<String> combinedCapabilities = new TreeSet<>();
-        StringBuilder modulesBuilder = new StringBuilder(), servicesBuilder = new StringBuilder();
+        List<ConfigSnapshotHolder> result = new ArrayList<>();
         for (File file : sortedFiles) {
             logger.trace("Adding file '{}' to combined result", file);
 
             final MyLineProcessor lineProcessor = new MyLineProcessor(file.getAbsolutePath());
             Files.readLines(file, ENCODING, lineProcessor);
-
-            modulesBuilder.append(lineProcessor.getModules());
-            servicesBuilder.append(lineProcessor.getServices());
-            combinedCapabilities.addAll(lineProcessor.getCapabilities());
+            result.add(lineProcessor.getConfigSnapshotHolder(header, middle, footer));
         }
-        String combinedSnapshot = header + modulesBuilder.toString() + middle + servicesBuilder.toString() + footer;
-        ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, combinedCapabilities);
-        return Optional.of(result);
+        return result;
     }
 
 
@@ -165,25 +160,11 @@ class MyLineProcessor implements com.google.common.io.LineProcessor<String> {
         return caps;
     }
 
-}
-
-class ConfigSnapshotHolderImpl implements ConfigSnapshotHolder {
-
-    private final String snapshot;
-    private final SortedSet<String> caps;
-
-    public ConfigSnapshotHolderImpl(String configSnapshot, SortedSet<String> capabilities) {
-        this.snapshot = configSnapshot;
-        this.caps = capabilities;
-    }
-
-    @Override
-    public String getConfigSnapshot() {
-        return snapshot;
+    ConfigSnapshotHolder getConfigSnapshotHolder(String header, String middle, String footer) {
+        String combinedSnapshot = header + getModules() + middle + getServices() + footer;
+        ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, getCapabilities(), fileNameForReporting);
+        return result;
     }
 
-    @Override
-    public SortedSet<String> getCapabilities() {
-        return caps;
-    }
 }
+
index 53ab4c210ef22497ffaa6a4b9a41d20894d719a7..f17e414c495e376b7316f9fcc79a1891313ad1a6 100644 (file)
@@ -8,14 +8,13 @@
 
 package org.opendaylight.controller.config.persist.storage.directory;
 
-import com.google.common.base.Optional;
 import org.apache.commons.io.IOUtils;
-import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 
 import java.io.File;
-import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
@@ -25,21 +24,13 @@ import static org.junit.Assert.fail;
 
 public class DirectoryStorageAdapterTest {
     DirectoryPersister tested;
-    SortedSet<String> expectedCapabilities;
-    String expectedSnapshot;
-
-    @Before
-    public void setUp() throws Exception {
-        expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/expectedCapabilities.txt")));
-        expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/expectedSnapshot.xml"));
-    }
 
     @Test
     public void testEmptyDirectory() throws Exception {
         File folder = new File("target/emptyFolder");
         folder.mkdir();
         tested = new DirectoryPersister((folder));
-        assertEquals(Optional.<ConfigSnapshotHolder>absent(), tested.loadLastConfig());
+        assertEquals(Collections.<ConfigSnapshotHolder>emptyList(), tested.loadLastConfigs());
 
         try {
             tested.persistConfig(new ConfigSnapshotHolder() {
@@ -70,22 +61,28 @@ public class DirectoryStorageAdapterTest {
     public void testOneFile() throws Exception {
         File folder = getFolder("oneFile");
         tested = new DirectoryPersister((folder));
-        assertExpected();
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(1, results.size());
+        ConfigSnapshotHolder result = results.get(0);
+        assertSnapshot(result, "oneFileExpected");
     }
 
-    private void assertExpected() throws IOException {
-        Optional<ConfigSnapshotHolder> maybeResult = tested.loadLastConfig();
-        assertTrue(maybeResult.isPresent());
-        ConfigSnapshotHolder result = maybeResult.get();
-        assertEquals(expectedCapabilities, result.getCapabilities());
-        assertEquals(expectedSnapshot, result.getConfigSnapshot());
-    }
 
     @Test
     public void testTwoFiles() throws Exception {
         File folder = getFolder("twoFiles");
         tested = new DirectoryPersister((folder));
-        assertExpected();
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(2, results.size());
+        assertSnapshot(results.get(0), "twoFilesExpected1");
+        assertSnapshot(results.get(1), "twoFilesExpected2");
+    }
+
+    private void assertSnapshot(ConfigSnapshotHolder result, String directory) throws Exception {
+        SortedSet<String> expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/" + directory + "/expectedCapabilities.txt")));
+        String expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/" + directory + "/expectedSnapshot.xml"));
+        assertEquals(expectedCapabilities, result.getCapabilities());
+        assertEquals(expectedSnapshot, result.getConfigSnapshot());
     }
 
 }
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt
new file mode 100644 (file)
index 0000000..ef35fdd
--- /dev/null
@@ -0,0 +1 @@
+urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml
new file mode 100644 (file)
index 0000000..2b1d06e
--- /dev/null
@@ -0,0 +1,84 @@
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+            <name>yang-schema-service</name>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+            <name>hash-map-data-store</name>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+            <name>dom-broker</name>
+            <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+                <name>ref_hash-map-data-store</name>
+            </data-store>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+            <name>binding-broker-impl</name>
+            <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+                <name>ref_binding-notification-broker</name>
+            </notification-service>
+            <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                <name>ref_binding-data-broker</name>
+            </data-broker>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+            <name>runtime-mapping-singleton</name>
+        </module>
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+            <name>binding-notification-broker</name>
+        </module>
+    </modules>
+    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+            <instance>
+                <name>ref_yang-schema-service</name>
+                <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+            <instance>
+                <name>ref_binding-notification-broker</name>
+                <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+            <instance>
+                <name>ref_hash-map-data-store</name>
+                <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <instance>
+                <name>ref_binding-broker-impl</name>
+                <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+            <instance>
+                <name>ref_runtime-mapping-singleton</name>
+                <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
+            </instance>
+        </service>
+        <service>
+            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+            <instance>
+                <name>ref_dom-broker</name>
+                <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
+            </instance>
+        </service>
+    </services>
+</data>
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt
new file mode 100644 (file)
index 0000000..9924111
--- /dev/null
@@ -0,0 +1,19 @@
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
+urn:ietf:params:netconf:capability:candidate:1.0
+urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04
+urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12
+urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
+urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24
+urn:ietf:params:netconf:capability:rollback-on-error:1.0
+urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24
+urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16
+urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09
+urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml
new file mode 100644 (file)
index 0000000..887cb2c
--- /dev/null
@@ -0,0 +1,25 @@
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+            <name>binding-data-broker</name>
+            <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                <name>ref_dom-broker</name>
+            </dom-broker>
+            <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+                <name>ref_runtime-mapping-singleton</name>
+            </mapping-service>
+        </module>
+    </modules>
+    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <service>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+            <instance>
+                <name>ref_binding-data-broker</name>
+                <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
+            </instance>
+        </service>
+    </services>
+</data>
index 66d0414d9a18485990ca709dd5ddc9832f1d4cf2..3ec8713b476514349c001f1854a4b9c05cc00ccf 100644 (file)
@@ -15,17 +15,19 @@ import com.google.common.base.Preconditions;
 import com.google.common.io.Files;
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
 import org.opendaylight.controller.config.persist.api.StorageAdapter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.xml.sax.SAXException;
 
-import javax.xml.parsers.ParserConfigurationException;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -105,7 +107,7 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
         } else {
             numberOfStoredBackups = Integer.MAX_VALUE;
         }
-
+        logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
         return result;
     }
 
@@ -164,27 +166,23 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
     }
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         Preconditions.checkNotNull(storage, "Storage file is null");
 
         if (!storage.exists()) {
-            return Optional.absent();
+            return Collections.emptyList();
         }
 
         final LineProcessor lineProcessor = new LineProcessor();
-        String result = Files.readLines(storage, ENCODING, lineProcessor);
-
-        try {
-            if (lineProcessor.getConfigSnapshot().isPresent() == false) {
-                return Optional.absent();
-            } else {
-                return Optional.<ConfigSnapshotHolder> of(new PersistedConfigImpl(lineProcessor.getConfigSnapshot(),
-                        lineProcessor.getCapabilities()));
-            }
+        Files.readLines(storage, ENCODING, lineProcessor);
 
-        } catch (ParserConfigurationException | SAXException e) {
-            throw new IOException("Unable to load last config ", e);
+        if (lineProcessor.getConfigSnapshot().isPresent() == false) {
+            return Collections.emptyList();
+        } else {
+            return Arrays.<ConfigSnapshotHolder>asList(new ConfigSnapshotHolderImpl(lineProcessor.getConfigSnapshot().get(),
+                    lineProcessor.getCapabilities(), storage.getAbsolutePath()));
         }
+
     }
 
     private static final class LineProcessor implements com.google.common.io.LineProcessor<String> {
@@ -227,15 +225,16 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
             return true;
         }
 
-        Optional<String> getConfigSnapshot() throws IOException, SAXException, ParserConfigurationException {
+        Optional<String> getConfigSnapshot() {
             final String xmlContent = snapshotBuffer.toString();
-            if (xmlContent == null || xmlContent.equals("")) {
+            if (xmlContent.equals("")) {
                 return Optional.absent();
-            } else
+            } else {
                 return Optional.of(xmlContent);
+            }
         }
 
-        SortedSet<String> getCapabilities() throws IOException, SAXException, ParserConfigurationException {
+        SortedSet<String> getCapabilities() {
             return caps;
         }
 
@@ -251,25 +250,4 @@ public class FileStorageAdapter implements StorageAdapter, Persister {
         return "FileStorageAdapter [storage=" + storage + "]";
     }
 
-    private class PersistedConfigImpl implements ConfigSnapshotHolder {
-
-        private final String snapshot;
-        private final SortedSet<String> caps;
-
-        public PersistedConfigImpl(Optional<String> configSnapshot, SortedSet<String> capabilities) {
-            this.snapshot = configSnapshot.get();
-            this.caps = capabilities;
-        }
-
-        @Override
-        public String getConfigSnapshot() {
-            return snapshot;
-        }
-
-        @Override
-        public SortedSet<String> getCapabilities() {
-            return caps;
-        }
-    }
-
 }
index ed50184aa7ad50d7e825fa6df2895271a99be834..0236598f2b877d995639072266beb042e9673c2e 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.config.persist.storage.file;
 
 import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import org.junit.Before;
@@ -20,11 +19,11 @@ import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import java.io.File;
 import java.nio.file.Files;
 import java.util.Collection;
+import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
 import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
@@ -75,11 +74,12 @@ public class FileStorageAdapterTest {
                 });
         assertEquals(14, readLines.size());
 
-        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
-        assertTrue(lastConf.isPresent());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
         assertEquals("<config>2</config>",
-                lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
-        assertEquals(createCaps(), lastConf.get().getCapabilities());
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
+        assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
     }
 
     private SortedSet<String> createCaps() {
@@ -123,10 +123,11 @@ public class FileStorageAdapterTest {
                 });
         assertEquals(7, readLines.size());
 
-        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
-        assertTrue(lastConf.isPresent());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
         assertEquals("<config>2</config>",
-                lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
     }
 
     @Test
@@ -163,10 +164,11 @@ public class FileStorageAdapterTest {
 
         assertEquals(14, readLines.size());
 
-        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
-        assertTrue(lastConf.isPresent());
+        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
+        assertEquals(1, lastConf.size());
+        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
         assertEquals("<config>3</config>",
-               lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
+                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
         assertFalse(readLines.contains(holder.getConfigSnapshot()));
     }
 
@@ -178,14 +180,14 @@ public class FileStorageAdapterTest {
         FileStorageAdapter storage = new FileStorageAdapter();
         storage.setFileStorage(file);
 
-        Optional<ConfigSnapshotHolder> elementOptional = storage.loadLastConfig();
-        assertThat(elementOptional.isPresent(), is(false));
+        List<ConfigSnapshotHolder> elementOptional = storage.loadLastConfigs();
+        assertThat(elementOptional.size(), is(0));
     }
 
     @Test(expected = NullPointerException.class)
     public void testNoProperties() throws Exception {
         FileStorageAdapter storage = new FileStorageAdapter();
-        storage.loadLastConfig();
+        storage.loadLastConfigs();
     }
 
     @Test(expected = NullPointerException.class)
index b0b6f3d74c131bb83c15cd0b6f5c3cd778ca3bb4..f721895921a8300b7afb0a368c0685e8a56ce871 100644 (file)
@@ -7,19 +7,9 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl;
 
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Pattern;
-
+import com.google.common.annotations.VisibleForTesting;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives.AnnotationsDirective;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives.ConstructorsDirective;
@@ -33,11 +23,18 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.directives
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.VisibleForTesting;
-
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
 
 public class FtlFilePersister {
     private static final Logger logger = LoggerFactory
@@ -56,7 +53,7 @@ public class FtlFilePersister {
                         ftlFile.getFtlTempleteLocation());
                 try {
                     template.process(ftlFile, writer);
-                } catch (TemplateException e) {
+                } catch (Throwable e) {
                     throw new IllegalStateException(
                             "Template error while generating " + ftlFile, e);
                 }
index 3a6ff18081961b9c6c15b68cc53e45a3e01369e0..6da68018f2ff92e3795c017b9ddadb2628a7e625 100644 (file)
@@ -21,13 +21,13 @@ import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute.Dependency;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation.Parameter;
@@ -39,6 +39,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Meth
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 
 import javax.management.openmbean.SimpleType;
@@ -112,8 +113,8 @@ public class TemplateFactory {
 
             // convert attributes to getters
             for (AttributeIfc attributeIfc : entry.getAttributes()) {
-                String returnType = null;
-                returnType = getReturnType(entry, attributeIfc);
+                String returnType;
+                returnType = getReturnType(attributeIfc);
                 String getterName = "get"
                         + attributeIfc.getUpperCaseCammelCase();
                 MethodDeclaration getter = new MethodDeclaration(returnType,
@@ -132,7 +133,7 @@ public class TemplateFactory {
                     fields.add(field);
                 }
                 MethodDeclaration operation = new MethodDeclaration(
-                        getReturnType(entry, rpc.getReturnType()), rpc.getName(), fields);
+                        getReturnType(rpc.getReturnType()), rpc.getName(), fields);
                 methods.add(operation);
             }
 
@@ -150,28 +151,35 @@ public class TemplateFactory {
         return result;
     }
 
-    private static String getReturnType(RuntimeBeanEntry entry, AttributeIfc attributeIfc) {
+    // FIXME: put into Type.toString
+    static String serializeType(Type type) {
+        if (type instanceof ParameterizedType){
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+            StringBuffer sb = new StringBuffer();
+            sb.append(parameterizedType.getRawType().getFullyQualifiedName());
+            sb.append("<");
+            boolean first = true;
+            for(Type parameter: parameterizedType.getActualTypeArguments()) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(",");
+                }
+                sb.append(serializeType(parameter));
+            }
+            sb.append(">");
+            return sb.toString();
+        } else {
+            return type.getFullyQualifiedName();
+        }
+    }
+
+
+    private static String getReturnType(AttributeIfc attributeIfc) {
         String returnType;
         if (attributeIfc instanceof TypedAttribute) {
-            returnType = ((TypedAttribute) attributeIfc).getType()
-                    .getFullyQualifiedName();
-        } else if (attributeIfc instanceof TOAttribute) {
-            String fullyQualifiedName = FullyQualifiedNameHelper
-                    .getFullyQualifiedName(entry.getPackageName(),
-                            attributeIfc.getUpperCaseCammelCase());
-
-            returnType = fullyQualifiedName;
-        } else if (attributeIfc instanceof ListAttribute) {
-            AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
-                    .getInnerAttribute();
-
-            String innerTpe = innerAttr instanceof TypedAttribute ? ((TypedAttribute) innerAttr)
-                    .getType().getFullyQualifiedName()
-                    : FullyQualifiedNameHelper.getFullyQualifiedName(
-                            entry.getPackageName(),
-                            attributeIfc.getUpperCaseCammelCase());
-
-            returnType = "java.util.List<" + innerTpe + ">";
+            Type type = ((TypedAttribute) attributeIfc).getType();
+            returnType = serializeType(type);
         } else if (attributeIfc == VoidAttribute.getInstance()) {
             return "void";
         } else {
@@ -292,8 +300,7 @@ public class TemplateFactory {
     public static GeneralInterfaceTemplate mXBeanInterfaceTemplateFromMbe(
             ModuleMXBeanEntry mbe) {
         MXBeanInterfaceAttributesProcessor attrProcessor = new MXBeanInterfaceAttributesProcessor();
-        attrProcessor.processAttributes(mbe.getAttributes(),
-                mbe.getPackageName());
+        attrProcessor.processAttributes(mbe.getAttributes());
         GeneralInterfaceTemplate ifcTemplate = new GeneralInterfaceTemplate(
                 getHeaderFromEntry(mbe), mbe.getPackageName(),
                 mbe.getMXBeanInterfaceName(), Lists.<String> newArrayList(),
@@ -306,7 +313,7 @@ public class TemplateFactory {
             ModuleMXBeanEntry mbe) {
         Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
         TOAttributesProcessor processor = new TOAttributesProcessor();
-        processor.processAttributes(mbe.getAttributes(), mbe.getPackageName());
+        processor.processAttributes(mbe.getAttributes());
         for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
                 .getTOs()) {
             List<Constructor> constructors = Lists.newArrayList();
@@ -345,7 +352,7 @@ public class TemplateFactory {
             yangPropertiesToTypesMap.put(returnType.getAttributeYangName(), returnType);
         }
 
-        processor.processAttributes(yangPropertiesToTypesMap, rbe.getPackageName());
+        processor.processAttributes(yangPropertiesToTypesMap);
         for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
                 .getTOs()) {
             List<Constructor> constructors = Lists.newArrayList();
@@ -372,36 +379,29 @@ public class TemplateFactory {
 
         private final List<TOInternal> tos = Lists.newArrayList();
 
-        void processAttributes(Map<String, AttributeIfc> attributes,
-                String packageName) {
+        void processAttributes(Map<String, AttributeIfc> attributes) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 AttributeIfc attributeIfc = attrEntry.getValue();
                 if (attributeIfc instanceof TOAttribute) {
-                    createTOInternal(packageName, attributeIfc);
+                    createTOInternal((TOAttribute) attributeIfc);
                 }
                 if (attributeIfc instanceof ListAttribute) {
                     AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
                             .getInnerAttribute();
                     if (innerAttr instanceof TOAttribute) {
-                        createTOInternal(packageName, innerAttr);
+                        createTOInternal((TOAttribute) innerAttr);
                     }
                 }
             }
         }
 
-        private void createTOInternal(String packageName,
-                AttributeIfc attributeIfc) {
-            String fullyQualifiedName = FullyQualifiedNameHelper
-                    .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
+        private void createTOInternal(TOAttribute toAttribute) {
 
-            String type = fullyQualifiedName;
-            String name = attributeIfc.getUpperCaseCammelCase();
-            Map<String, AttributeIfc> attrs = ((TOAttribute) attributeIfc)
-                    .getCapitalizedPropertiesToTypesMap();
-            // recursive processing
-            processAttributes(attrs, packageName);
+            Map<String, AttributeIfc> attrs = toAttribute.getCapitalizedPropertiesToTypesMap();
+            // recursive processing of TO's attributes
+            processAttributes(attrs);
 
-            tos.add(new TOInternal(type, name, attrs, packageName));
+            tos.add(new TOInternal(toAttribute.getType(), attrs));
         }
 
         List<TOInternal> getTOs() {
@@ -409,20 +409,22 @@ public class TemplateFactory {
         }
 
         private static class TOInternal {
-            private final String type, name;
+            private final String fullyQualifiedName, name;
             private List<Field> fields;
             private List<MethodDefinition> methods;
 
-            public TOInternal(String type, String name,
+            public TOInternal(Type type, Map<String, AttributeIfc> attrs) {
+                this(type.getFullyQualifiedName(), type.getName(), attrs, type.getPackageName());
+            }
+
+            public TOInternal(String fullyQualifiedName, String name,
                     Map<String, AttributeIfc> attrs, String packageName) {
-                super();
-                this.type = type;
+                this.fullyQualifiedName = fullyQualifiedName;
                 this.name = name;
                 processAttrs(attrs, packageName);
             }
 
-            private void processAttrs(Map<String, AttributeIfc> attrs,
-                    String packageName) {
+            private void processAttrs(Map<String, AttributeIfc> attrs, String packageName) {
                 fields = Lists.newArrayList();
                 methods = Lists.newArrayList();
 
@@ -431,25 +433,14 @@ public class TemplateFactory {
                     String varName = BindingGeneratorUtil
                             .parseToValidParamName(attrEntry.getKey());
 
-                    String fullyQualifiedName = null;
+                    String fullyQualifiedName;
                     if (attrEntry.getValue() instanceof TypedAttribute) {
-                        Type innerType = ((TypedAttribute) attrEntry.getValue())
-                                .getType();
-                        fullyQualifiedName = innerType.getFullyQualifiedName();
-                    } else if (attrEntry.getValue() instanceof ListAttribute) {
-                        AttributeIfc innerAttr = ((ListAttribute) attrEntry
-                                .getValue()).getInnerAttribute();
-
-                        String innerTpe = innerAttr instanceof TypedAttribute ? ((TypedAttribute) innerAttr)
-                                .getType().getFullyQualifiedName()
-                                : FullyQualifiedNameHelper
-                                        .getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
-
-                        fullyQualifiedName = "java.util.List<" + innerTpe + ">";
-                    } else
+                        Type type = ((TypedAttribute) attrEntry.getValue()).getType();
+                        fullyQualifiedName = serializeType(type);
+                    } else {
                         fullyQualifiedName = FullyQualifiedNameHelper
                                 .getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
-
+                    }
                     fields.add(new Field(fullyQualifiedName, varName));
 
                     String getterName = "get" + innerName;
@@ -470,7 +461,7 @@ public class TemplateFactory {
             }
 
             String getType() {
-                return type;
+                return fullyQualifiedName;
             }
 
             String getName() {
@@ -488,38 +479,16 @@ public class TemplateFactory {
     }
 
     private static class MXBeanInterfaceAttributesProcessor {
-        private static final String STRING_FULLY_QUALIFIED_NAME = "java.util.List";
         private final List<MethodDeclaration> methods = Lists.newArrayList();
 
-        void processAttributes(Map<String, AttributeIfc> attributes,
-                String packageName) {
+        void processAttributes(Map<String, AttributeIfc> attributes) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 String returnType;
                 AttributeIfc attributeIfc = attrEntry.getValue();
 
                 if (attributeIfc instanceof TypedAttribute) {
-                    returnType = ((TypedAttribute) attributeIfc).getType()
-                            .getFullyQualifiedName();
-                } else if (attributeIfc instanceof TOAttribute) {
-                    String fullyQualifiedName = FullyQualifiedNameHelper
-                            .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
-
-                    returnType = fullyQualifiedName;
-                } else if (attributeIfc instanceof ListAttribute) {
-                    String fullyQualifiedName = null;
-
-                    AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
-                            .getInnerAttribute();
-                    if (innerAttr instanceof JavaAttribute) {
-                        fullyQualifiedName = ((JavaAttribute) innerAttr)
-                                .getType().getFullyQualifiedName();
-                    } else if (innerAttr instanceof TOAttribute) {
-                        fullyQualifiedName = FullyQualifiedNameHelper
-                                .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
-                    }
-
-                    returnType = STRING_FULLY_QUALIFIED_NAME.concat("<")
-                            .concat(fullyQualifiedName).concat(">");
+                    TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+                    returnType = serializeType(typedAttribute.getType());
                 } else {
                     throw new UnsupportedOperationException(
                             "Attribute not supported: "
@@ -565,14 +534,14 @@ public class TemplateFactory {
                 AttributeIfc attributeIfc = attrEntry.getValue();
 
                 if (attributeIfc instanceof TypedAttribute) {
-                    type = ((TypedAttribute) attributeIfc).getType()
-                            .getFullyQualifiedName();
+                    TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+                    type = serializeType(typedAttribute.getType());
                 } else if (attributeIfc instanceof TOAttribute) {
                     String fullyQualifiedName = FullyQualifiedNameHelper
                             .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
 
                     type = fullyQualifiedName;
-                } else if (attributeIfc instanceof ListAttribute) {
+                } else if (attributeIfc instanceof ListAttribute) {  //FIXME: listAttribute might extend TypedAttribute
                     String fullyQualifiedName = null;
                     AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
                             .getInnerAttribute();
@@ -617,8 +586,8 @@ public class TemplateFactory {
                 AttributeIfc attributeIfc = attrEntry.getValue();
 
                 if (attributeIfc instanceof TypedAttribute) {
-                    type = ((TypedAttribute) attributeIfc).getType()
-                            .getFullyQualifiedName();
+                    TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
+                    type = serializeType(typedAttribute.getType());
                 } else if (attributeIfc instanceof TOAttribute) {
                     String fullyQualifiedName = FullyQualifiedNameHelper
                             .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
@@ -651,9 +620,9 @@ public class TemplateFactory {
                 List<Annotation> annotations = Lists
                         .newArrayList(overrideAnnotation);
 
-                if (attributeIfc instanceof DependencyAttribute) {
+                if (attributeIfc instanceof AbstractDependencyAttribute) {
                     isDependency = true;
-                    dependency = ((DependencyAttribute) attributeIfc)
+                    dependency = ((AbstractDependencyAttribute) attributeIfc)
                             .getDependency();
                     annotations.add(Annotation
                             .createRequireIfcAnnotation(dependency.getSie()));
index 293696d10e0887e3157412d9653bc87878791ef8..5624e169da81d0f69dc2bca15f7dce1de71fab6a 100644 (file)
@@ -7,11 +7,13 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model;
 
+
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute.Dependency;
-
 public class ModuleField extends Field {
 
     private final String nullableDefault, attributeName;
@@ -22,10 +24,14 @@ public class ModuleField extends Field {
             String attributeName, String nullableDefault, boolean isDependency,
             Dependency dependency) {
         super(modifiers, type, name);
-        this.nullableDefault = nullableDefault;
         this.dependent = isDependency;
         this.dependency = dependency;
         this.attributeName = attributeName;
+        if (type.startsWith(List.class.getName()) && nullableDefault == null) {
+            String generics = type.substring(List.class.getName().length());
+            nullableDefault = "new " + ArrayList.class.getName() + generics + "()";
+        }
+        this.nullableDefault = nullableDefault;
     }
 
     public ModuleField(String type, String name, String attributeName,
@@ -49,4 +55,5 @@ public class ModuleField extends Field {
     public String getAttributeName() {
         return attributeName;
     }
+
 }
index d0646f467a50416a71bb7d5f5c0c42cdfd343abf..f7197d1582ca70193cb21591922f8c77529a31ed 100644 (file)
@@ -52,8 +52,14 @@ package ${packageName};
     public void validate(){
     <#list moduleFields as field>
         <#if field.dependent==true && field.dependency.mandatory==true>
+        <#if field.type?starts_with("java.util.List")>
+        for(javax.management.ObjectName dep : ${field.name}) {
+            dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, dep, ${field.name}JmxAttribute);
+        }
+        <#else>
         dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, ${field.name}, ${field.name}JmxAttribute);
         </#if>
+        </#if>
     </#list>
         customValidation();
     }
@@ -65,10 +71,17 @@ package ${packageName};
     // caches of resolved dependencies
     <#list moduleFields as field>
     <#if field.dependent==true>
+        <#if field.type?starts_with("java.util.List")>
+        private java.util.List<${field.dependency.sie.exportedOsgiClassName}> ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
+        protected final java.util.List<${field.dependency.sie.exportedOsgiClassName}> get${field.attributeName}Dependency(){
+            return ${field.name}Dependency;
+        }
+        <#else>
         private ${field.dependency.sie.exportedOsgiClassName} ${field.name}Dependency;
         protected final ${field.dependency.sie.exportedOsgiClassName} get${field.attributeName}Dependency(){
             return ${field.name}Dependency;
         }
+        </#if>
     </#if>
     </#list>
 
@@ -79,12 +92,18 @@ package ${packageName};
 
             <#list moduleFields as field>
                 <#if field.dependent==true>
-
                     <#if field.dependency.mandatory==false>
                         if(${field.name}!=null) {
                     </#if>
 
-                    ${field.name}Dependency = dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, ${field.name}, ${field.name}JmxAttribute);
+                    <#if field.type?starts_with("java.util.List")>
+            ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
+            for(javax.management.ObjectName dep : ${field.name}) {
+                ${field.name}Dependency.add(dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, dep, ${field.name}JmxAttribute));
+            }
+                    <#else>
+            ${field.name}Dependency = dependencyResolver.resolveInstance(${field.dependency.sie.exportedOsgiClassName}.class, ${field.name}, ${field.name}JmxAttribute);
+                    </#if>
 
                     <#if field.dependency.mandatory==false>
                         }
index 0d6ec3cccbeedf872bbd61c8649f6c66cf743a63..2f1437404a7d49f7673d0c6ae34637f597be6847 100644 (file)
@@ -75,6 +75,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 
+//TODO: refactor
 public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     JMXGenerator jmxGenerator;
@@ -84,19 +85,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
     File generatedResourcesDir;
 
     private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
-            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
-                    "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
-                    "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
-                    "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
-                    "AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
-                    "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
-                    "AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, " +
-                    "DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, " +
-                    "DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, " +
-                    "DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, " +
-                    "EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
-                    "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
-                    "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
 
     private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
             .toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
@@ -119,38 +108,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                     "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
                     "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java]");
     private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
-            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, " +
-                    "AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, " +
-                    "AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, " +
-                    "AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, " +
-                    "AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, " +
-                    "AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, " +
-                    "AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, " +
-                    "AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, " +
-                    "AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, " +
-                    "AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, " +
-                    "AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AsyncEventBusModule.java, " +
-                    "AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, " +
-                    "AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, " +
-                    "AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, " +
-                    "BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java," +
-                    " BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, " +
-                    "BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, " +
-                    "DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, " +
-                    "DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, " +
-                    "DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, " +
-                    "DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, " +
-                    "EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, " +
-                    "EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, " +
-                    "InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, " +
-                    "NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, " +
-                    "NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, " +
-                    "NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, " +
-                    "NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, " +
-                    "NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, " +
-                    "NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, " +
-                    "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
-                    "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
     private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
             .toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
 
@@ -381,7 +339,11 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
                         + ".threads.java.DynamicThreadPoolModuleFactory",//
                 PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
-                        + ".threads.java.NamingThreadFactoryModuleFactory");
+                        + ".threads.java.NamingThreadFactoryModuleFactory", //
+                PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+                        + ".threads.java.ThreadPoolRegistryImplModuleFactory");
+
+
         assertThat(lines, equalTo(expectedLines));
 
     }
index 70a4edde41b70aa82852482fb24455ef0fee264d..a7110b874c829e00cfaccf4386abf97fb9c7b556 100644 (file)
@@ -8,11 +8,14 @@
 package org.opendaylight.controller.config.yangjmxgenerator;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
 import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
@@ -21,6 +24,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
@@ -338,7 +342,7 @@ public class ModuleMXBeanEntry extends AbstractEntry {
                                 moduleLocalNameFromXPath);
                         yangToAttributes = fillConfiguration(choiceCaseNode,
                                 currentModule, typeProviderWrapper,
-                                qNamesToSIEs, schemaContext);
+                                qNamesToSIEs, schemaContext, packageName);
                         checkUniqueAttributesWithGeneratedClass(
                                 uniqueGeneratedClassesNames, when.getQName(),
                                 yangToAttributes);
@@ -484,12 +488,12 @@ public class ModuleMXBeanEntry extends AbstractEntry {
             ChoiceCaseNode choiceCaseNode, Module currentModule,
             TypeProviderWrapper typeProviderWrapper,
             Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            SchemaContext schemaContext) {
+            SchemaContext schemaContext, String packageName) {
         Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
         for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
             AttributeIfc attributeValue = getAttributeValue(attrNode,
                     currentModule, qNamesToSIEs, typeProviderWrapper,
-                    schemaContext);
+                    schemaContext, packageName);
             yangToAttributes.put(attributeValue.getAttributeYangName(),
                     attributeValue);
         }
@@ -549,11 +553,12 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         }
     }
 
-    private static int getChildNodeSizeWithoutUses(ContainerSchemaNode csn) {
+    private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
         int result = 0;
         for (DataSchemaNode dsn : csn.getChildNodes()) {
-            if (dsn.isAddedByUses() == false)
+            if (dsn.isAddedByUses() == false) {
                 result++;
+            }
         }
         return result;
     }
@@ -561,7 +566,7 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     private static AttributeIfc getAttributeValue(DataSchemaNode attrNode,
             Module currentModule,
             Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            TypeProviderWrapper typeProviderWrapper, SchemaContext schemaContext) {
+            TypeProviderWrapper typeProviderWrapper, SchemaContext schemaContext, String packageName) {
 
         if (attrNode instanceof LeafSchemaNode) {
             // simple type
@@ -570,49 +575,75 @@ public class ModuleMXBeanEntry extends AbstractEntry {
         } else if (attrNode instanceof ContainerSchemaNode) {
             // reference or TO
             ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
-            if (containerSchemaNode.getUses().size() == 1
-                    && getChildNodeSizeWithoutUses(containerSchemaNode) == 0) {
-                // reference
-                UsesNode usesNode = containerSchemaNode.getUses().iterator()
-                        .next();
-                checkState(usesNode.getRefines().size() == 1,
-                        "Unexpected 'refine' child node size of "
-                                + containerSchemaNode);
-                LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
-                        .values().iterator().next();
-                checkState(refine.getUnknownSchemaNodes().size() == 1,
-                        "Unexpected unknown schema node size of " + refine);
-                UnknownSchemaNode requiredIdentity = refine
-                        .getUnknownSchemaNodes().iterator().next();
-                checkState(
-                        ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
-                                .getNodeType()),
-                        "Unexpected language extension " + requiredIdentity);
-                String prefixAndIdentityLocalName = requiredIdentity
-                        .getNodeParameter();
-                // import should point to a module
-                ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
-                        prefixAndIdentityLocalName, currentModule,
-                        qNamesToSIEs, schemaContext);
-                boolean mandatory = refine.getConstraints().isMandatory();
-                return new DependencyAttribute(attrNode, serviceInterfaceEntry,
-                        mandatory, attrNode.getDescription());
+            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(containerSchemaNode,
+                    attrNode, currentModule, qNamesToSIEs, schemaContext);
+            if (dependencyAttributeOptional.isPresent()) {
+                return dependencyAttributeOptional.get();
             } else {
-                return TOAttribute.create(containerSchemaNode,
-                        typeProviderWrapper);
+                return TOAttribute.create(containerSchemaNode, typeProviderWrapper, packageName);
             }
+
         } else if (attrNode instanceof LeafListSchemaNode) {
             return ListAttribute.create((LeafListSchemaNode) attrNode,
                     typeProviderWrapper);
         } else if (attrNode instanceof ListSchemaNode) {
-            return ListAttribute.create((ListSchemaNode) attrNode,
-                    typeProviderWrapper);
+            ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
+            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(listSchemaNode,
+                    attrNode, currentModule, qNamesToSIEs, schemaContext);
+            if (dependencyAttributeOptional.isPresent()) {
+                return dependencyAttributeOptional.get();
+            } else {
+                return ListAttribute.create(listSchemaNode, typeProviderWrapper, packageName);
+            }
         } else {
             throw new UnsupportedOperationException(
                     "Unknown configuration node " + attrNode.toString());
         }
     }
 
+    private static Optional<? extends AbstractDependencyAttribute> extractDependency(DataNodeContainer dataNodeContainer,
+                                                            DataSchemaNode attrNode,
+                                                            Module currentModule,
+                                                            Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+                                                            SchemaContext schemaContext) {
+        if (dataNodeContainer.getUses().size() == 1
+                && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
+            // reference
+            UsesNode usesNode = dataNodeContainer.getUses().iterator()
+                    .next();
+            checkState(usesNode.getRefines().size() == 1,
+                    "Unexpected 'refine' child node size of "
+                            + dataNodeContainer);
+            LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
+                    .values().iterator().next();
+            checkState(refine.getUnknownSchemaNodes().size() == 1,
+                    "Unexpected unknown schema node size of " + refine);
+            UnknownSchemaNode requiredIdentity = refine
+                    .getUnknownSchemaNodes().iterator().next();
+            checkState(
+                    ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
+                            .getNodeType()),
+                    "Unexpected language extension " + requiredIdentity);
+            String prefixAndIdentityLocalName = requiredIdentity
+                    .getNodeParameter();
+            // import should point to a module
+            ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
+                    prefixAndIdentityLocalName, currentModule,
+                    qNamesToSIEs, schemaContext);
+            boolean mandatory = refine.getConstraints().isMandatory();
+            AbstractDependencyAttribute reference;
+            if (dataNodeContainer instanceof ContainerSchemaNode ){
+                reference = new DependencyAttribute(attrNode, serviceInterfaceEntry,
+                    mandatory, attrNode.getDescription());
+            } else {
+                reference = new ListDependenciesAttribute(attrNode, serviceInterfaceEntry,
+                        mandatory, attrNode.getDescription());
+            }
+            return Optional.of(reference);
+        }
+        return Optional.absent();
+    }
+
     private static ServiceInterfaceEntry findSIE(
             String prefixAndIdentityLocalName, Module currentModule,
             Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
index 9b82f123caf97f88a40b813d507c29ab2a06ee00..f19a46d0f461e35a1ecf9dd97e05aa1500a821df 100644 (file)
@@ -67,7 +67,7 @@ public class RuntimeBeanEntry {
     private final Set<Rpc> rpcs;
 
     @VisibleForTesting
-    public RuntimeBeanEntry(String packageName,
+    RuntimeBeanEntry(String packageName,
             DataSchemaNode nodeForReporting, String yangName,
             String javaNamePrefix, boolean isRoot,
             Optional<String> keyYangName, List<AttributeIfc> attributes,
@@ -228,7 +228,7 @@ public class RuntimeBeanEntry {
                 ContainerSchemaNode container = (ContainerSchemaNode) child;
                 // this can be either TO or hierarchical RB
                 TOAttribute toAttribute = TOAttribute.create(container,
-                        typeProviderWrapper);
+                        typeProviderWrapper, packageName);
                 attributes.add(toAttribute);
             } else if (child instanceof ListSchemaNode) {
                 if (isInnerStateBean(child)) {
@@ -239,7 +239,7 @@ public class RuntimeBeanEntry {
                     runtimeBeanEntries.add(hierarchicalChild);
                 } else /* ordinary list attribute */{
                     ListAttribute listAttribute = ListAttribute.create(
-                            (ListSchemaNode) child, typeProviderWrapper);
+                            (ListSchemaNode) child, typeProviderWrapper, packageName);
                     attributes.add(listAttribute);
                 }
 
@@ -280,7 +280,7 @@ public class RuntimeBeanEntry {
                     } else if (rpcDefinition.getOutput().getChildNodes().size() == 1) {
                         DataSchemaNode returnDSN = rpcDefinition.getOutput()
                                 .getChildNodes().iterator().next();
-                        returnType = getReturnTypeAttribute(returnDSN, typeProviderWrapper);
+                        returnType = getReturnTypeAttribute(returnDSN, typeProviderWrapper, packageName);
 
                     } else {
                         throw new IllegalArgumentException(
@@ -311,16 +311,17 @@ public class RuntimeBeanEntry {
                 attributes, rpcs);
     }
 
-    private static AttributeIfc getReturnTypeAttribute(DataSchemaNode child, TypeProviderWrapper typeProviderWrapper) {
+    private static AttributeIfc getReturnTypeAttribute(DataSchemaNode child, TypeProviderWrapper typeProviderWrapper,
+                                                       String packageName) {
         if (child instanceof LeafSchemaNode) {
             LeafSchemaNode leaf = (LeafSchemaNode) child;
             return new JavaAttribute(leaf, typeProviderWrapper);
         } else if (child instanceof ContainerSchemaNode) {
             ContainerSchemaNode container = (ContainerSchemaNode) child;
-            TOAttribute toAttribute = TOAttribute.create(container, typeProviderWrapper);
+            TOAttribute toAttribute = TOAttribute.create(container, typeProviderWrapper, packageName);
             return toAttribute;
         } else if (child instanceof ListSchemaNode) {
-            return ListAttribute.create((ListSchemaNode) child, typeProviderWrapper);
+            return ListAttribute.create((ListSchemaNode) child, typeProviderWrapper, packageName);
         } else if (child instanceof LeafListSchemaNode) {
             return ListAttribute.create((LeafListSchemaNode) child, typeProviderWrapper);
         } else {
diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java
new file mode 100644 (file)
index 0000000..eb1c9e4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public abstract class AbstractDependencyAttribute extends AbstractAttribute  implements TypedAttribute  {
+
+    protected final Dependency dependency;
+    protected final String nullableDescription, nullableDefault;
+
+    public AbstractDependencyAttribute(DataSchemaNode attrNode,
+                                       ServiceInterfaceEntry sie, boolean mandatory,
+                                       String nullableDescription) {
+        super(attrNode);
+        dependency = new Dependency(sie, mandatory);
+        this.nullableDescription = nullableDescription;
+        nullableDefault = null;
+    }
+
+    public Dependency getDependency() {
+        return dependency;
+    }
+
+    @Override
+    public String getNullableDescription() {
+        return nullableDescription;
+    }
+
+    @Override
+    public String getNullableDefault() {
+        return nullableDefault;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        if (!super.equals(o))
+            return false;
+
+        AbstractDependencyAttribute that = (AbstractDependencyAttribute) o;
+
+        if (dependency != null ? !dependency.equals(that.dependency)
+                : that.dependency != null)
+            return false;
+        if (nullableDefault != null ? !nullableDefault
+                .equals(that.nullableDefault) : that.nullableDefault != null)
+            return false;
+        if (nullableDescription != null ? !nullableDescription
+                .equals(that.nullableDescription)
+                : that.nullableDescription != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (dependency != null ? dependency.hashCode() : 0);
+        result = 31
+                * result
+                + (nullableDescription != null ? nullableDescription.hashCode()
+                        : 0);
+        result = 31 * result
+                + (nullableDefault != null ? nullableDefault.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getName() + "{" + getAttributeYangName() + ","
+                + "dependency=" + dependency + '}';
+    }
+
+
+}
diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Dependency.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Dependency.java
new file mode 100644 (file)
index 0000000..38de6e1
--- /dev/null
@@ -0,0 +1,45 @@
+package org.opendaylight.controller.config.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+
+public class Dependency {
+        private final ServiceInterfaceEntry sie;
+        private final boolean mandatory;
+
+        public Dependency(ServiceInterfaceEntry sie, boolean mandatory) {
+            this.sie = sie;
+            this.mandatory = mandatory;
+        }
+
+        public ServiceInterfaceEntry getSie() {
+            return sie;
+        }
+
+        public boolean isMandatory() {
+            return mandatory;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Dependency that = (Dependency) o;
+
+            if (mandatory != that.mandatory)
+                return false;
+            if (!sie.equals(that.sie))
+                return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = sie.hashCode();
+            result = 31 * result + (mandatory ? 1 : 0);
+            return result;
+        }
+    }
index 1912b75e0ee740c31634c2e709650a7d0c33728a..d8df78af0ae7103660241e8842064d0def753c47 100644 (file)
@@ -15,19 +15,13 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import javax.management.ObjectName;
 import javax.management.openmbean.SimpleType;
 
-public class DependencyAttribute extends AbstractAttribute implements
-        TypedAttribute {
+public class DependencyAttribute extends AbstractDependencyAttribute {
 
-    private final Dependency dependency;
-    private final String nullableDescription, nullableDefault;
 
     public DependencyAttribute(DataSchemaNode attrNode,
             ServiceInterfaceEntry sie, boolean mandatory,
             String nullableDescription) {
-        super(attrNode);
-        dependency = new Dependency(sie, mandatory);
-        this.nullableDescription = nullableDescription;
-        nullableDefault = null;
+        super(attrNode, sie, mandatory, nullableDescription);
     }
 
     @Override
@@ -35,109 +29,9 @@ public class DependencyAttribute extends AbstractAttribute implements
         return Types.typeForClass(ObjectName.class);
     }
 
-    public Dependency getDependency() {
-        return dependency;
-    }
-
-    @Override
-    public String getNullableDescription() {
-        return nullableDescription;
-    }
-
-    @Override
-    public String getNullableDefault() {
-        return nullableDefault;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (o == null || getClass() != o.getClass())
-            return false;
-        if (!super.equals(o))
-            return false;
-
-        DependencyAttribute that = (DependencyAttribute) o;
-
-        if (dependency != null ? !dependency.equals(that.dependency)
-                : that.dependency != null)
-            return false;
-        if (nullableDefault != null ? !nullableDefault
-                .equals(that.nullableDefault) : that.nullableDefault != null)
-            return false;
-        if (nullableDescription != null ? !nullableDescription
-                .equals(that.nullableDescription)
-                : that.nullableDescription != null)
-            return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = super.hashCode();
-        result = 31 * result + (dependency != null ? dependency.hashCode() : 0);
-        result = 31
-                * result
-                + (nullableDescription != null ? nullableDescription.hashCode()
-                        : 0);
-        result = 31 * result
-                + (nullableDefault != null ? nullableDefault.hashCode() : 0);
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "DependencyAttribute{" + getAttributeYangName() + ","
-                + "dependency=" + dependency + '}';
-    }
-
     @Override
     public SimpleType<?> getOpenType() {
         return SimpleType.OBJECTNAME;
     }
 
-    public static class Dependency {
-        private final ServiceInterfaceEntry sie;
-        private final boolean mandatory;
-
-        public Dependency(ServiceInterfaceEntry sie, boolean mandatory) {
-            this.sie = sie;
-            this.mandatory = mandatory;
-        }
-
-        public ServiceInterfaceEntry getSie() {
-            return sie;
-        }
-
-        public boolean isMandatory() {
-            return mandatory;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o)
-                return true;
-            if (o == null || getClass() != o.getClass())
-                return false;
-
-            Dependency that = (Dependency) o;
-
-            if (mandatory != that.mandatory)
-                return false;
-            if (!sie.equals(that.sie))
-                return false;
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = sie.hashCode();
-            result = 31 * result + (mandatory ? 1 : 0);
-            return result;
-        }
-    }
-
 }
index 083b0b53e9777c2391acafb65e72011267800183..73b557e291c03385823fb214fb0a96054d2b6610 100644 (file)
@@ -7,24 +7,27 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.attribute;
 
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-
 import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 
-public class ListAttribute extends AbstractAttribute {
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import java.util.List;
+
+public class ListAttribute extends AbstractAttribute implements TypedAttribute {
 
     private final String nullableDescription, nullableDefault;
-    private final AttributeIfc innerAttribute;
+    private final TypedAttribute innerAttribute;
 
     public static ListAttribute create(ListSchemaNode node,
-            TypeProviderWrapper typeProvider) {
+            TypeProviderWrapper typeProvider, String packageName) {
 
-        AttributeIfc innerAttribute = TOAttribute.create(node, typeProvider);
+        TOAttribute innerAttribute = TOAttribute.create(node, typeProvider, packageName);
 
         return new ListAttribute(node, innerAttribute, node.getDescription());
     }
@@ -32,12 +35,12 @@ public class ListAttribute extends AbstractAttribute {
     public static ListAttribute create(LeafListSchemaNode node,
             TypeProviderWrapper typeProvider) {
 
-        AttributeIfc innerAttribute = new JavaAttribute(node, typeProvider);
+        JavaAttribute innerAttribute = new JavaAttribute(node, typeProvider);
 
         return new ListAttribute(node, innerAttribute, node.getDescription());
     }
 
-    ListAttribute(DataSchemaNode attrNode, AttributeIfc innerAttribute,
+    ListAttribute(DataSchemaNode attrNode, TypedAttribute innerAttribute,
             String description) {
         super(attrNode);
         this.nullableDescription = description;
@@ -99,14 +102,24 @@ public class ListAttribute extends AbstractAttribute {
         return true;
     }
 
+
+    @Override
+    public Type getType() {
+        return Types.parameterizedTypeFor(Types.typeForClass(List.class), innerAttribute.getType());
+    }
+
     @Override
     public ArrayType<?> getOpenType() {
-        OpenType<?> inerOpenType = innerAttribute.getOpenType();
+        OpenType<?> innerOpenType = innerAttribute.getOpenType();
+        return constructArrayType(innerOpenType);
+    }
+
+    static ArrayType<?> constructArrayType(OpenType<?> innerOpenType){
         try {
-            return new ArrayType<>(1, inerOpenType);
+            return new ArrayType<>(1, innerOpenType);
         } catch (OpenDataException e) {
             throw new RuntimeException("Unable to create " + ArrayType.class
-                    + " with inner element of type " + inerOpenType, e);
+                    + " with inner element of type " + innerOpenType, e);
         }
     }
 
diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListDependenciesAttribute.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListDependenciesAttribute.java
new file mode 100644 (file)
index 0000000..641099a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.yangjmxgenerator.attribute;
+
+import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
+import org.opendaylight.yangtools.binding.generator.util.Types;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+import javax.management.ObjectName;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import java.util.List;
+
+public class ListDependenciesAttribute extends AbstractDependencyAttribute {
+
+    public ListDependenciesAttribute(DataSchemaNode attrNode, ServiceInterfaceEntry sie, boolean mandatory, String nullableDescription) {
+        super(attrNode, sie, mandatory, nullableDescription);
+    }
+
+    @Override
+    public Type getType() {
+        return Types.parameterizedTypeFor(Types.typeForClass(List.class), Types.typeForClass(ObjectName.class));
+    }
+
+    @Override
+    public ArrayType<?> getOpenType() {
+        OpenType<?> innerOpenType = SimpleType.OBJECTNAME;
+        return ListAttribute.constructArrayType(innerOpenType);
+    }
+
+}
index 96656338df130f30ef569fbb54537727ff9a0b3a..6a540b50b21dab04433dcb349eb905a9a2cd303b 100644 (file)
@@ -13,6 +13,8 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -29,11 +31,12 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-public class TOAttribute extends AbstractAttribute {
+public class TOAttribute extends AbstractAttribute implements TypedAttribute {
 
     private final String nullableDescription, nullableDefault;
     private final Map<String, AttributeIfc> yangNameToAttributeMap;
     private final Map<String, String> attributeNameMap;
+    private final String packageName;
 
     private static final Set<Class<? extends DataSchemaNode>> ALLOWED_CHILDREN = Sets
             .newHashSet();
@@ -45,7 +48,7 @@ public class TOAttribute extends AbstractAttribute {
     }
 
     public static <T extends DataNodeContainer & AugmentationTarget & DataSchemaNode> TOAttribute create(
-            T containerSchemaNode, TypeProviderWrapper typeProviderWrapper) {
+            T containerSchemaNode, TypeProviderWrapper typeProviderWrapper, String packageName) {
         // Transfer Object: get the leaves
         Map<String, AttributeIfc> map = new HashMap<>();
         Map<String, String> attributeNameMap = new HashMap<>();
@@ -55,18 +58,18 @@ public class TOAttribute extends AbstractAttribute {
                 String yangName = dataSchemaNode.getQName().getLocalName();
                 map.put(yangName,
                         createInnerAttribute(dataSchemaNode,
-                                typeProviderWrapper));
+                                typeProviderWrapper, packageName));
             } catch (IllegalArgumentException e) {
                 throw new IllegalStateException("Unable to create TO", e);
             }
         }
         return new TOAttribute(containerSchemaNode, map, attributeNameMap,
-                containerSchemaNode.getDescription());
+                containerSchemaNode.getDescription(), packageName);
     }
 
     private static AttributeIfc createInnerAttribute(
             DataSchemaNode dataSchemaNode,
-            TypeProviderWrapper typeProviderWrapper) {
+            TypeProviderWrapper typeProviderWrapper, String packageName) {
         Class<? extends DataSchemaNode> type = isAllowedType(dataSchemaNode);
 
         if (type.equals(LeafSchemaNode.class))
@@ -74,13 +77,13 @@ public class TOAttribute extends AbstractAttribute {
                     typeProviderWrapper);
         else if (type.equals(ListSchemaNode.class))
             return ListAttribute.create((ListSchemaNode) dataSchemaNode,
-                    typeProviderWrapper);
+                    typeProviderWrapper, packageName);
         else if (type.equals(LeafListSchemaNode.class))
             return ListAttribute.create((LeafListSchemaNode) dataSchemaNode,
                     typeProviderWrapper);
         else if (type.equals(ContainerSchemaNode.class))
             return TOAttribute.create((ContainerSchemaNode) dataSchemaNode,
-                    typeProviderWrapper);
+                    typeProviderWrapper, packageName);
 
         throw new IllegalStateException("This should never happen");
     }
@@ -98,12 +101,13 @@ public class TOAttribute extends AbstractAttribute {
 
     private TOAttribute(DataSchemaNode attrNode,
             Map<String, AttributeIfc> transferObject,
-            Map<String, String> attributeNameMap, String nullableDescription) {
+            Map<String, String> attributeNameMap, String nullableDescription, String packageName) {
         super(attrNode);
         yangNameToAttributeMap = transferObject;
         this.attributeNameMap = attributeNameMap;
         this.nullableDescription = nullableDescription;
         nullableDefault = null;
+        this.packageName = packageName;
     }
 
     public Map<String, String> getAttributeNameMap() {
@@ -197,6 +201,12 @@ public class TOAttribute extends AbstractAttribute {
                 + yangNameToAttributeMap + '}';
     }
 
+    @Override
+    public Type getType() {
+        // TODO: ReferencedTypeImpl from Types
+        return new ReferencedTypeImpl(packageName, getUpperCaseCammelCase());
+    }
+
     @Override
     public CompositeType getOpenType() {
         String description = getNullableDescription() == null ? getAttributeYangName()
@@ -222,6 +232,10 @@ public class TOAttribute extends AbstractAttribute {
         }
     }
 
+    public String getPackageName() {
+        return packageName;
+    }
+
     private static final class FunctionImpl implements
             Function<Entry<String, AttributeIfc>, OpenType<?>> {
         private final String[] itemNames;
index 661dbd7da344e6006e393313cd3f80a2ea9b90cd..e86c87616941d297cb3752a6f727203269a09b3d 100644 (file)
@@ -7,38 +7,14 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.SimpleType;
-
+import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -48,13 +24,37 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
 
-import com.google.common.collect.Sets;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.SimpleType;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 public class ModuleMXBeanEntryTest extends AbstractYangTest {
     public static final String EVENTBUS_MXB_NAME = "eventbus";
     public static final String ASYNC_EVENTBUS_MXB_NAME = "async-eventbus";
     public static final String THREADFACTORY_NAMING_MXB_NAME = "threadfactory-naming";
     public static final String THREADPOOL_DYNAMIC_MXB_NAME = "threadpool-dynamic";
+    public static final String THREADPOOL_REGISTRY_IMPL_NAME = "threadpool-registry-impl";
 
     public static final String BGP_LISTENER_IMPL_MXB_NAME = "bgp-listener-impl";
 
@@ -87,7 +87,7 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest {
         assertNotNull(namesToMBEs);
         Set<String> expectedMXBeanNames = Sets.newHashSet(EVENTBUS_MXB_NAME,
                 ASYNC_EVENTBUS_MXB_NAME, THREADFACTORY_NAMING_MXB_NAME,
-                THREADPOOL_DYNAMIC_MXB_NAME);
+                THREADPOOL_DYNAMIC_MXB_NAME, THREADPOOL_REGISTRY_IMPL_NAME);
         assertThat(namesToMBEs.keySet(), is(expectedMXBeanNames));
         return namesToMBEs;
     }
@@ -299,6 +299,15 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest {
             }
 
         }
+        { // test multiple dependencies
+            ModuleMXBeanEntry threadPoolRegistry = namesToMBEs.get(THREADPOOL_REGISTRY_IMPL_NAME);
+            Map<String, AttributeIfc> attributes = threadPoolRegistry.getAttributes();
+            assertEquals(1, attributes.size());
+            AttributeIfc threadpoolsAttr = attributes.get("threadpools");
+            assertNotNull(threadpoolsAttr);
+            assertTrue(threadpoolsAttr instanceof ListDependenciesAttribute);
+            ListDependenciesAttribute threadpools = (ListDependenciesAttribute) threadpoolsAttr;
+        }
     }
 
 }
index 24c025755bdc906219d247c2cfe033cacffa5be8..14ec7e0fdc9bfae4b97dd5ffe2705f67834b0e61 100644 (file)
@@ -100,10 +100,15 @@ public class SchemaContextTest extends AbstractYangTest {
 
     @Test
     public void testReadingIdentities_threadsJavaModule() {
-        Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = ImmutableMap
-                .of("eventbus", Optional.of(MODULE_TYPE_Q_NAME), "async-eventbus", Optional.of(MODULE_TYPE_Q_NAME),
-                        "threadfactory-naming", Optional.of(MODULE_TYPE_Q_NAME), "threadpool-dynamic",
-                        Optional.of(MODULE_TYPE_Q_NAME), "thread-rpc-context", Optional.<QName>absent());
+        Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = new HashMap(){{
+            put(ModuleMXBeanEntryTest.EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put(ModuleMXBeanEntryTest.ASYNC_EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put(ModuleMXBeanEntryTest.THREADFACTORY_NAMING_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put(ModuleMXBeanEntryTest.THREADPOOL_DYNAMIC_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+            put("thread-rpc-context", Optional.absent());
+            put(ModuleMXBeanEntryTest.THREADPOOL_REGISTRY_IMPL_NAME, Optional.of(MODULE_TYPE_Q_NAME));
+        }};
+
         assertAllIdentitiesAreExpected(threadsJavaModule,
                 expectedIdentitiesToBases);
     }
index 2972cec04fc7eefe607fd94e0441a92656ca93b1..4af5b9569a445dfba4d601d18c7f76bf0f64ba0a 100644 (file)
@@ -241,4 +241,25 @@ module config-threads-java {
             }
         }
     }
+
+    identity threadpool-registry-impl {
+        base config:module-type;
+        config:java-name-prefix ThreadPoolRegistryImpl;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case threadpool-registry-impl {
+            when "/config:modules/config:module/config:type = 'threadpool-registry-impl'";
+
+            // list of dependencies:
+            list threadpools {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity th2:threadpool;
+                    }
+                }
+            }
+        }
+    }
 }
index ba5021ea099361fd5d548e318a6448811020177f..bd83a4cc701c358fc85829e1098fb21d73806505 100644 (file)
@@ -242,6 +242,15 @@ module config-test-impl {
                     }
                 }
             }
+
+            list testing-deps {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity test:testing;
+                    }
+                }
+            }
         }
     }
 
index 35ebbbe0dd2455394a06f5ff62e731b57012ac6d..adc0c0973f76309d60b474c5e1dfbddc5fa23e9d 100644 (file)
           <artifactId>config-netconf-connector</artifactId>
           <version>${netconf.version}</version>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>netconf-monitoring</artifactId>
+          <version>${netconf.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>${project.groupId}</groupId>
+          <artifactId>ietf-netconf-monitoring</artifactId>
+          <version>${netconf.version}</version>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>config-persister-impl</artifactId>
index de7597730f9062a85d7071b3986044c4874a4e7a..3ec9f8443a1264063ef79c4f192c0a9c9ea727ca 100644 (file)
@@ -836,21 +836,14 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile("OUTPUT=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
-                        if (n.matches()) {
-                            String port = n.group(1);
-                            if (port != null) {
-                                if (!isPortValid(sw, port)) {
-                                    String msg = String.format("Output port %s is not valid for this switch", port);
-                                    if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                                        msg += " in Container " + containerName;
-                                    }
-                                    return new Status(StatusCode.BADREQUEST, msg);
+                        if (t != null) {
+                            if (!isPortValid(sw, t)) {
+                                String msg = String.format("Output port %s is not valid for this switch", t);
+                                if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
+                                    msg += " in Container " + containerName;
                                 }
+                                return new Status(StatusCode.BADREQUEST, msg);
                             }
-                        } else {
-                            String msg = String.format("Output port %s is not valid", t);
-                            return new Status(StatusCode.BADREQUEST, msg);
                         }
                     }
                     continue;
@@ -859,21 +852,15 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile("ENQUEUE=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+:\\d+))").matcher(t);
-                        if (n.matches()) {
-                            if (n.group(1) != null) {
-                                String port = n.group(1).split(":")[0];
-                                if (!isPortValid(sw, port)) {
-                                    String msg = String.format("Output port %d is not valid for this switch", port);
-                                    if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
-                                        msg += " in Container " + containerName;
-                                    }
-                                    return new Status(StatusCode.BADREQUEST, msg);
+                        if (t != null) {
+                            String port = t.split(":")[0];
+                            if (!isPortValid(sw, port)) {
+                                String msg = String.format("Output port %d is not valid for this switch", port);
+                                if (!containerName.equals(GlobalConstants.DEFAULT.toString())) {
+                                    msg += " in Container " + containerName;
                                 }
+                                return new Status(StatusCode.BADREQUEST, msg);
                             }
-                        } else {
-                            String msg = String.format("Enqueue port %s is not valid", t);
-                            return new Status(StatusCode.BADREQUEST, msg);
                         }
                     }
                     continue;
@@ -1102,12 +1089,9 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile(ActionType.OUTPUT + "=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+))").matcher(t);
-                        if (n.matches()) {
-                            if (n.group(1) != null) {
-                                String nc = String.format("%s|%s@%s", node.getType(), n.group(1), node.toString());
-                                actionList.add(new Output(NodeConnector.fromString(nc)));
-                            }
+                        if (t != null) {
+                            String nc = String.format("%s|%s@%s", node.getType(), t, node.toString());
+                            actionList.add(new Output(NodeConnector.fromString(nc)));
                         }
                     }
                     continue;
@@ -1116,17 +1100,14 @@ public class FlowConfig implements Serializable {
                 sstr = Pattern.compile(ActionType.ENQUEUE + "=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     for (String t : sstr.group(1).split(",")) {
-                        Matcher n = Pattern.compile("(?:(\\d+:\\d+))").matcher(t);
-                        if (n.matches()) {
-                            if (n.group(1) != null) {
-                                String parts[] = n.group(1).split(":");
-                                String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
-                                if (parts.length == 1) {
-                                    actionList.add(new Enqueue(NodeConnector.fromString(nc)));
-                                } else {
-                                    actionList
-                                            .add(new Enqueue(NodeConnector.fromString(nc), Integer.parseInt(parts[1])));
-                                }
+                        if (t != null) {
+                            String parts[] = t.split(":");
+                            String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
+                            if (parts.length == 1) {
+                                actionList.add(new Enqueue(NodeConnector.fromString(nc)));
+                            } else {
+                                actionList
+                                .add(new Enqueue(NodeConnector.fromString(nc), Integer.parseInt(parts[1])));
                             }
                         }
                     }
index d28e8e1fd18994979d211821680eb2ff7339eec9..6fbbd4d6e289ce87de6f3ee0e9b119fdaa795e5b 100644 (file)
@@ -38,6 +38,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.Rem
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
@@ -53,7 +54,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @SuppressWarnings("unused")
-public class GroupConsumerImpl implements IForwardingRulesManager {
+public class GroupConsumerImpl {
 
     protected static final Logger logger = LoggerFactory.getLogger(GroupConsumerImpl.class);
     private final GroupEventListener groupEventListener = new GroupEventListener();
@@ -61,24 +62,12 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
     private SalGroupService groupService;
     private GroupDataCommitHandler groupCommitHandler;
 
-    private ConcurrentMap<GroupKey, Group> originalSwGroupView;
-    private ConcurrentMap<GroupKey, Group> installedSwGroupView;
-
-    private ConcurrentMap<Node, List<Group>> nodeGroups;
-    private ConcurrentMap<GroupKey, Group> inactiveGroups;
-
-    private IClusterContainerServices clusterGroupContainerService = null;
     private IContainer container;
 
     public GroupConsumerImpl() {
 
         InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Groups.class).toInstance();
-        groupService = FRMConsumerImpl.getProviderSession().getRpcService(SalGroupService.class);
-
-        if (!(cacheStartup())) {
-            logger.error("Unanle to allocate/retrieve group cache");
-            System.out.println("Unable to allocate/retrieve group cache");
-        }
+        groupService = FRMConsumerImpl.getProviderSession().getRpcService(SalGroupService.class);      
 
         if (null == groupService) {
             logger.error("Consumer SAL Group Service is down or NULL. FRM may not function as intended");
@@ -97,130 +86,15 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
 
         groupCommitHandler = new GroupDataCommitHandler();
         FRMConsumerImpl.getDataProviderService().registerCommitHandler(path, groupCommitHandler);
-        clusterGroupContainerService = FRMConsumerImpl.getClusterContainerService();
-        container = FRMConsumerImpl.getContainer();
-    }
-
-    private boolean allocateGroupCaches() {
-        if (this.clusterGroupContainerService == null) {
-            logger.warn("Group: Un-initialized clusterGroupContainerService, can't create cache");
-            return false;
-        }
-
-        try {
-            clusterGroupContainerService.createCache("frm.originalSwGroupView",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            clusterGroupContainerService.createCache("frm.installedSwGroupView",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            clusterGroupContainerService.createCache("frm.inactiveGroups",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            clusterGroupContainerService.createCache("frm.nodeGroups",
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
-            // TODO for cluster mode
-            /*
-             * clusterGroupContainerService.createCache(WORK_STATUS_CACHE,
-             * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
-             * IClusterServices.cacheMode.ASYNC));
-             *
-             * clusterGroupContainerService.createCache(WORK_ORDER_CACHE,
-             * EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL,
-             * IClusterServices.cacheMode.ASYNC));
-             */
-
-        } catch (CacheConfigException cce) {
-            logger.error("Group CacheConfigException");
-            return false;
-
-        } catch (CacheExistException cce) {
-            logger.error(" Group CacheExistException");
-        }
-
-        return true;
-    }
-
-    private void nonClusterGroupObjectCreate() {
-        originalSwGroupView = new ConcurrentHashMap<GroupKey, Group>();
-        installedSwGroupView = new ConcurrentHashMap<GroupKey, Group>();
-        nodeGroups = new ConcurrentHashMap<Node, List<Group>>();
-        inactiveGroups = new ConcurrentHashMap<GroupKey, Group>();
-    }
-
-    @SuppressWarnings({ "unchecked" })
-    private boolean retrieveGroupCaches() {
-        ConcurrentMap<?, ?> map;
-
-        if (this.clusterGroupContainerService == null) {
-            logger.warn("Group: un-initialized clusterGroupContainerService, can't retrieve cache");
-            nonClusterGroupObjectCreate();
-            return false;
-        }
+    }  
 
-        map = clusterGroupContainerService.getCache("frm.originalSwGroupView");
-        if (map != null) {
-            originalSwGroupView = (ConcurrentMap<GroupKey, Group>) map;
-        } else {
-            logger.error("Retrieval of cache(originalSwGroupView) failed");
-            return false;
-        }
-
-        map = clusterGroupContainerService.getCache("frm.installedSwGroupView");
-        if (map != null) {
-            installedSwGroupView = (ConcurrentMap<GroupKey, Group>) map;
-        } else {
-            logger.error("Retrieval of cache(installedSwGroupView) failed");
-            return false;
-        }
-
-        map = clusterGroupContainerService.getCache("frm.inactiveGroups");
-        if (map != null) {
-            inactiveGroups = (ConcurrentMap<GroupKey, Group>) map;
-        } else {
-            logger.error("Retrieval of cache(inactiveGroups) failed");
-            return false;
-        }
-
-        map = clusterGroupContainerService.getCache("frm.nodeGroups");
-        if (map != null) {
-            nodeGroups = (ConcurrentMap<Node, List<Group>>) map;
-        } else {
-            logger.error("Retrieval of cache(nodeGroup) failed");
-            return false;
-        }
-
-        return true;
-    }
-
-    private boolean cacheStartup() {
-        if (allocateGroupCaches()) {
-            if (retrieveGroupCaches()) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    public Status validateGroup(Group group, FRMUtil.operation operation) {
-        String containerName;
+    public Status validateGroup(Group group) {        
         String groupName;
         Iterator<Bucket> bucketIterator;
         boolean returnResult;
         Buckets groupBuckets;
 
-        if (null != group) {
-            containerName = group.getContainerName();
-
-            if (null == containerName) {
-                containerName = GlobalConstants.DEFAULT.toString();
-            } else if (!FRMUtil.isNameValid(containerName)) {
-                logger.error("Container Name is invalid %s" + containerName);
-                return new Status(StatusCode.BADREQUEST, "Container Name is invalid");
-            }
-            
+        if (null != group) {   
             groupName = group.getGroupName();
             if (!FRMUtil.isNameValid(groupName)) {
                 logger.error("Group Name is invalid %s" + groupName);
@@ -257,24 +131,28 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
      * @param path
      * @param dataObject
      */
-    private Status updateGroup(InstanceIdentifier<?> path, Group groupUpdateDataObject) {
-        GroupKey groupKey = groupUpdateDataObject.getKey();
+    private void updateGroup(InstanceIdentifier<?> path, 
+        Group originalGroupDataObject, Group updatedGroupDataObject) {
+        
+        GroupKey groupKey = updatedGroupDataObject.getKey();
+       // Node nodeInstanceID = path.firstIdentifierOf("Node");
         UpdatedGroupBuilder updateGroupBuilder = null;
-
-        Status groupOperationStatus = validateGroup(groupUpdateDataObject, FRMUtil.operation.UPDATE);
+        Status groupOperationStatus = validateGroup(updatedGroupDataObject);
 
         if (!groupOperationStatus.isSuccess()) {
-            logger.error("Group data object validation failed %s" + groupUpdateDataObject.getGroupName());
-            return groupOperationStatus;
+            logger.error("Group data object validation failed %s" + updatedGroupDataObject.getGroupName());
+            return;
         }
         
-        UpdateGroupInputBuilder groupData = new UpdateGroupInputBuilder();
-        updateGroupBuilder = new UpdatedGroupBuilder();
-        updateGroupBuilder.setGroupId(new GroupId(groupUpdateDataObject.getId()));
-        updateGroupBuilder.fieldsFrom(groupUpdateDataObject);
-        groupData.setUpdatedGroup(updateGroupBuilder.build());        
-        groupService.updateGroup(groupData.build());
-        return groupOperationStatus;
+        UpdateGroupInputBuilder groupInputBuilder = new UpdateGroupInputBuilder();
+        groupInputBuilder.setNode(updatedGroupDataObject.getNode());
+        updateGroupBuilder = new UpdatedGroupBuilder(updatedGroupDataObject);
+        updateGroupBuilder.setGroupId(new GroupId(updatedGroupDataObject.getId()));        
+        groupInputBuilder.setUpdatedGroup(updateGroupBuilder.build());       
+        OriginalGroupBuilder originalGroupBuilder = new OriginalGroupBuilder(originalGroupDataObject);
+        groupInputBuilder.setOriginalGroup(originalGroupBuilder.build());
+        groupService.updateGroup(groupInputBuilder.build());
+        return;
     }
 
     /**
@@ -283,13 +161,13 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
      * @param path
      * @param dataObject
      */
-    private Status addGroup(InstanceIdentifier<?> path, Group groupAddDataObject) {
+    private void addGroup(InstanceIdentifier<?> path, Group groupAddDataObject) {
         GroupKey groupKey = groupAddDataObject.getKey();
-        Status groupOperationStatus = validateGroup(groupAddDataObject, FRMUtil.operation.ADD);
+        Status groupOperationStatus = validateGroup(groupAddDataObject);
 
         if (!groupOperationStatus.isSuccess()) {
             logger.error("Group data object validation failed %s" + groupAddDataObject.getGroupName());
-            return groupOperationStatus;
+            return;
         }
         
         AddGroupInputBuilder groupData = new AddGroupInputBuilder();
@@ -299,7 +177,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
         groupData.setGroupType(groupAddDataObject.getGroupType());
         groupData.setNode(groupAddDataObject.getNode());    
         groupService.addGroup(groupData.build());
-        return groupOperationStatus;
+        return;
     }
 
     /**
@@ -308,13 +186,13 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
      * @param path
      * @param dataObject
      */
-    private Status removeGroup(InstanceIdentifier<?> path, Group groupRemoveDataObject) {
+    private void removeGroup(InstanceIdentifier<?> path, Group groupRemoveDataObject) {
         GroupKey groupKey = groupRemoveDataObject.getKey();
-        Status groupOperationStatus = validateGroup(groupRemoveDataObject, FRMUtil.operation.ADD);
+        Status groupOperationStatus = validateGroup(groupRemoveDataObject);
 
         if (!groupOperationStatus.isSuccess()) {
             logger.error("Group data object validation failed %s" + groupRemoveDataObject.getGroupName());
-            return groupOperationStatus;
+            return;
         }
        
         RemoveGroupInputBuilder groupData = new RemoveGroupInputBuilder();
@@ -324,34 +202,45 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
         groupData.setGroupType(groupRemoveDataObject.getGroupType());
         groupData.setNode(groupRemoveDataObject.getNode());    
         groupService.removeGroup(groupData.build());  
-        return groupOperationStatus;
+        return;
     }
     
     private RpcResult<Void> commitToPlugin(InternalTransaction transaction) {
-        for (Entry<InstanceIdentifier<?>, Group> entry : transaction.additions.entrySet()) {
-
-            if (!addGroup(entry.getKey(), entry.getValue()).isSuccess()) {
-                transaction.additions.remove(entry.getKey());
-                return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
-            }
-        }
-
-        for (Entry<InstanceIdentifier<?>, Group> entry : transaction.updates.entrySet()) {
-
-            if (!addGroup(entry.getKey(), entry.getValue()).isSuccess()) {
-                transaction.updates.remove(entry.getKey());
-                return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet());
-            }
-        }
+        DataModification<InstanceIdentifier<?>, DataObject> modification = transaction.modification;         
+        //get created entries      
+        Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = 
+                                        modification.getCreatedConfigurationData().entrySet();
+        
+        //get updated entries
+        Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = 
+                    new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>(); 
+        
+        updatedEntries.addAll(modification.getUpdatedConfigurationData().entrySet());
+        updatedEntries.removeAll(createdEntries);
 
-        for (InstanceIdentifier<?> groupId : transaction.removals) {
-                       DataObject removeValue = transaction.getModification().getOriginalConfigurationData().get(groupId);     
-                
-                       if(removeValue instanceof Group) {
-                           if(!removeGroup(groupId, (Group)removeValue).isSuccess()) {
-                               return Rpcs.getRpcResult(false, null, Collections.<RpcError>emptySet()); 
-                           }             
-                       }
+        //get removed entries
+        Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = 
+                                                    modification.getRemovedConfigurationData();
+        
+        for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) { 
+            if(entry.getValue() instanceof Group) {   
+                addGroup(entry.getKey(), (Group)entry.getValue());   
+            }   
+        } 
+        
+        for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) { 
+            if(entry.getValue() instanceof Group) {   
+                Group originalGroup = (Group) modification.getOriginalConfigurationData().get(entry.getKey());    
+                Group updatedGroup = (Group) entry.getValue(); 
+                updateGroup(entry.getKey(), originalGroup, updatedGroup);   
+            }   
+        }   
+
+        for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {    
+            DataObject removeValue = modification.getOriginalConfigurationData().get(instanceId);   
+            if(removeValue instanceof Group) {   
+                removeGroup(instanceId, (Group)removeValue); 
+            }   
         }
 
         return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
@@ -361,32 +250,21 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
 
         @Override
         public DataCommitTransaction<InstanceIdentifier<?>, DataObject> requestCommit(
-                DataModification<InstanceIdentifier<?>, DataObject> modification) {
-            // We should verify transaction
-            System.out.println("Coming in GroupDatacommitHandler");
+                DataModification<InstanceIdentifier<?>, DataObject> modification) {            
             InternalTransaction transaction = new InternalTransaction(modification);
             transaction.prepareUpdate();
             return transaction;
         }
     }
 
-    private final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {
+    private final class InternalTransaction implements DataCommitTransaction<InstanceIdentifier<?>, DataObject> {      
 
         private final DataModification<InstanceIdentifier<?>, DataObject> modification;
-
-        @Override
-        public DataModification<InstanceIdentifier<?>, DataObject> getModification() {
-            return modification;
-        }
-
-        public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {
+        
+        public InternalTransaction(DataModification<InstanceIdentifier<?>, DataObject> modification) {   
             this.modification = modification;
         }
-
-        Map<InstanceIdentifier<?>, Group> additions = new HashMap<>();
-        Map<InstanceIdentifier<?>, Group> updates = new HashMap<>();
-        Set<InstanceIdentifier<?>> removals = new HashSet<>();
-
+        
         /**
          * We create a plan which flows will be added, which will be updated and
          * which will be removed based on our internal state.
@@ -394,28 +272,6 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
          */
         void prepareUpdate() {
                
-                Set<Entry<InstanceIdentifier<?>, DataObject>> groupAdded = modification.getCreatedConfigurationData().entrySet();
-             for (Entry<InstanceIdentifier<?>, DataObject> entry : groupAdded) {
-                 if (entry.getValue() instanceof Group) {
-                     Group group = (Group) entry.getValue();
-                     additions.put(entry.getKey(), group);                     
-                 }
-
-             }
-
-            Set<Entry<InstanceIdentifier<?>, DataObject>> groupUpdate = modification.getUpdatedConfigurationData().entrySet();
-            for (Entry<InstanceIdentifier<?>, DataObject> entry : groupUpdate) {
-                if (entry.getValue() instanceof Group) {
-                    Group group = (Group) entry.getValue();
-                    ///will be fixed once getUpdatedConfigurationData returns only updated data not created data with it.
-                    if (additions.containsKey(entry.getKey())) {
-                       updates.put(entry.getKey(), group);
-                    }
-                }
-
-            }
-
-            removals = modification.getRemovedConfigurationData();
         }
         
         /**
@@ -425,9 +281,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
         @Override
         public RpcResult<Void> finish() throws IllegalStateException {
 
-            RpcResult<Void> rpcStatus = commitToPlugin(this);
-            // We return true if internal transaction is successful.
-            // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+            RpcResult<Void> rpcStatus = commitToPlugin(this);            
             return rpcStatus;
         }
 
@@ -437,12 +291,15 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
          *
          */
         @Override
-        public RpcResult<Void> rollback() throws IllegalStateException {
-            // NOOP - we did not modified any internal state during
-            // requestCommit phase
-            // return Rpcs.getRpcResult(true, null, Collections.emptySet());
+        public RpcResult<Void> rollback() throws IllegalStateException { 
+            
+            ///needs to be implemented as per gerrit 3314
             return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
+        }
 
+        @Override
+        public DataModification<InstanceIdentifier<?>, DataObject> getModification() {            
+            return modification;
         }
 
     }
@@ -470,31 +327,4 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
 
         }
     }
-
-    @Override
-    public List<DataObject> get() {
-
-        List<DataObject> orderedList = new ArrayList<DataObject>();
-        Collection<Group> groupList = originalSwGroupView.values();
-        for (Iterator<Group> iterator = groupList.iterator(); iterator.hasNext();) {
-            orderedList.add(iterator.next());
-        }
-        return orderedList;
-    }
-
-    @Override
-    public DataObject getWithName(String name, Node n) {
-
-        if (this instanceof GroupConsumerImpl) {
-            Collection<Group> groupList = originalSwGroupView.values();
-            for (Iterator<Group> iterator = groupList.iterator(); iterator.hasNext();) {
-                Group group = iterator.next();
-                if (group.getNode().equals(n) && group.getGroupName().equals(name)) {
-
-                    return group;
-                }
-            }
-        }
-        return null;
-    }
-}
+ }
index f58f6a459741e569578c5133b8e6d118e953d2a6..5ba92aba9d2f242be04e05b11e18892872d53c3f 100644 (file)
@@ -91,11 +91,6 @@ module opendaylight-match-types {
             description "IP ECN (2 bits in ToS field).";
             type uint8; 
         }
-        
-        leaf ip-proto {
-            description "IP Proto (IPv4 or IPv6 Protocol Number).";
-            type inet:ip-version; 
-        }
     } 
     
     grouping "ipv4-match-fields" {
@@ -146,10 +141,16 @@ module opendaylight-match-types {
             description "Link layer target address for neighbour discovery message";
             type yang:mac-address;
         }
-            
-        leaf ipv6-exthdr {
-            description "IPv6 Extension Header field";
-            type uint16;
+        
+        container "ipv6-ext-header" {    
+            leaf ipv6-exthdr {
+                description "IPv6 Extension Header field";
+                type uint16;
+            }
+
+            leaf ipv6-exthdr-mask {
+                type binary;
+            }
         }
     }
 
index 6a994dbd07c6295d9284bfae5bf270523c4e8785..235e6ac51efcafa22dd8b6e18368d71eaff07a7f 100644 (file)
             <artifactId>netconf-impl</artifactId>
             <version>${netconf.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>netconf-monitoring</artifactId>
+            <version>${netconf.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>netconf-client</artifactId>
index 49781ce11630a7f589dda76922e1107025b9abba..15616215d35f13950c08167abe7b687490ba1078 100644 (file)
@@ -53,6 +53,8 @@ public class TestHelper {
                 mavenBundle(CONTROLLER, "logback-config").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "config-persister-api").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-api").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "ietf-netconf-monitoring").versionAsInProject(), //
+                mavenBundle(CONTROLLER, "netconf-monitoring").versionAsInProject(), //
 
                 mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-util").versionAsInProject(), //
index 4b6dcfd46528b3068fe2a7c41dc9b9224f205b9c..2b6f862bd7dc17ed8cb3960a81fe951721b7888e 100644 (file)
@@ -12,6 +12,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIf
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 
 import javax.management.openmbean.ArrayType;
@@ -37,7 +38,9 @@ public abstract class AttributeIfcSwitchStatement<T> {
         } else if (attributeIfc instanceof DependencyAttribute) {
             return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType());
         } else if (attributeIfc instanceof ListAttribute) {
-            return caseListAttribute(((ListAttribute) attributeIfc).getOpenType());
+            return caseListAttribute((ArrayType<?>) attributeIfc.getOpenType());
+        } else if (attributeIfc instanceof ListDependenciesAttribute) {
+            return caseListDependeciesAttribute((ArrayType<?>) attributeIfc.getOpenType());
         } else if (attributeIfc instanceof TOAttribute) {
             return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType());
         }
@@ -45,6 +48,7 @@ public abstract class AttributeIfcSwitchStatement<T> {
         throw getIllegalArgumentException(attributeIfc);
     }
 
+
     private IllegalArgumentException getIllegalArgumentException(AttributeIfc attributeIfc) {
         return new IllegalArgumentException("Unknown attribute type " + attributeIfc.getClass() + ", " + attributeIfc
                 + " with open type:" + attributeIfc.getOpenType());
@@ -74,6 +78,7 @@ public abstract class AttributeIfcSwitchStatement<T> {
 
     protected abstract T caseListAttribute(ArrayType<?> openType);
 
+    protected abstract T caseListDependeciesAttribute(ArrayType<?> openType);
 
     private static class UnknownOpenTypeException extends RuntimeException {
         public UnknownOpenTypeException(String message) {
index bc3c74a88f218aa01ad82a97976ee704df8d1f86..e2ea404e2158f40c0d56ada00994e8fcd371da82 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 
@@ -86,4 +87,11 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadin
         return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
     }
 
+    @Override
+    protected AttributeReadingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        AttributeReadingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
+        return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
+    }
+
 }
index 853197c0b089b7ca1dd32bdf09486a5b8b72f849..6e5bd0d3fe8229597ab6984f37150f1833cd3525 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
@@ -121,4 +122,10 @@ public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingSt
                 prepareStrategy(((ListAttribute) lastAttribute).getInnerAttribute()));
     }
 
+    @Override
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        return new ArrayAttributeMappingStrategy(openType, caseDependencyAttribute(SimpleType.OBJECTNAME));
+    }
+
 }
index c321164cf6b29c02548d9239787de2686d26e521..f5a25112602ac6b92c6d08faa46b311dbd11533c 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
@@ -109,4 +110,10 @@ public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvi
         return new ArrayAttributeResolvingStrategy(prepareStrategy(innerAttribute), openType);
     }
 
+    @Override
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        return new ArrayAttributeResolvingStrategy(caseDependencyAttribute(SimpleType.OBJECTNAME), openType);
+    }
+
 }
index 99e969970ccbd9ec27926979a5d597ab2b1f8881..ad587ea9879b41ca06f59020f41b0be0ba5fb536 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 import org.w3c.dom.Document;
@@ -96,4 +97,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritin
         return new ArrayAttributeWritingStrategy(innerStrategy);
     }
 
+    @Override
+    protected AttributeWritingStrategy caseListDependeciesAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListDependenciesAttribute);
+        AttributeWritingStrategy innerStrategy = caseDependencyAttribute(SimpleType.OBJECTNAME);
+        return new ArrayAttributeWritingStrategy(innerStrategy);
+    }
+
 }
index e4fa6f504b7b86799c1276875c2471a5719f5892..f522668733497333b7b2ac2052fe5949985f8f51 100644 (file)
@@ -284,8 +284,13 @@ public final class Services {
         public static ServiceInstance fromString(String instanceId) {
             instanceId = instanceId.trim();
             Matcher matcher = p.matcher(instanceId);
+            if(matcher.matches() == false) {
+                matcher = pDeprecated.matcher(instanceId);
+            }
+
             Preconditions.checkArgument(matcher.matches(), "Unexpected format for provider, expected " + p.toString()
-                    + " but was " + instanceId);
+                    + " or " + pDeprecated.toString() + " but was " + instanceId);
+
             String factoryName = matcher.group(1);
             String instanceName = matcher.group(2);
             return new ServiceInstance(factoryName, instanceName);
@@ -310,16 +315,25 @@ public final class Services {
             return instanceName;
         }
 
-        private static final String blueprint = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+        private static final String blueprint = "/"
                 + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "["
-                + XmlNetconfConstants.NAME_KEY + "='%s']/" + XmlNetconfConstants.INSTANCE_KEY + "["
+                + XmlNetconfConstants.TYPE_KEY + "='%s']["
                 + XmlNetconfConstants.NAME_KEY + "='%s']";
 
-        private static final String blueprintR = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
+        // TODO unify with xpath in RuntimeRpc
+
+        // Previous version of xpath, needs to be supported for backwards compatibility (persisted configs by config-persister)
+        private static final String blueprintRDeprecated = "/" + XmlNetconfConstants.CONFIG_KEY + "/"
                 + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
                 + XmlNetconfConstants.NAME_KEY + "='%s'\\]/" + XmlNetconfConstants.INSTANCE_KEY + "\\["
                 + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
 
+        private static final String blueprintR = "/"
+                + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\["
+                + XmlNetconfConstants.TYPE_KEY + "='%s'\\]\\["
+                + XmlNetconfConstants.NAME_KEY + "='%s'\\]";
+
+        private static final Pattern pDeprecated = Pattern.compile(String.format(blueprintRDeprecated, "(.+)", "(.+)"));
         private static final Pattern p = Pattern.compile(String.format(blueprintR, "(.+)", "(.+)"));
 
         @Override
index 84a9f395207d0c6afcf3d3199cbb31abebd61f85..7ee13aeb589c713351f760464f19a4aff48647d3 100644 (file)
@@ -40,8 +40,6 @@ import java.util.Set;
 
 public class Get extends AbstractConfigNetconfOperation {
 
-    public static final String GET = "get";
-
     private final YangStoreSnapshot yangStoreSnapshot;
     private static final Logger logger = LoggerFactory.getLogger(Get.class);
 
@@ -102,17 +100,17 @@ public class Get extends AbstractConfigNetconfOperation {
     }
 
     private static void checkXml(XmlElement xml) {
-        xml.checkName(GET);
+        xml.checkName(XmlNetconfConstants.GET);
         xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
 
         // Filter option - unsupported
         if (xml.getChildElements(XmlNetconfConstants.FILTER).size() != 0)
-            throw new UnsupportedOperationException("Unsupported option " + XmlNetconfConstants.FILTER + " for " + GET);
+            throw new UnsupportedOperationException("Unsupported option " + XmlNetconfConstants.FILTER + " for " + XmlNetconfConstants.GET);
     }
 
     @Override
     protected String getOperationName() {
-        return GET;
+        return XmlNetconfConstants.GET;
     }
 
     @Override
@@ -148,7 +146,7 @@ public class Get extends AbstractConfigNetconfOperation {
 
         final Element element = runtime.toXml(runtimeBeans, configBeans, document);
 
-        logger.info("{} operation successful", GET);
+        logger.info("{} operation successful", XmlNetconfConstants.GET);
 
         return element;
     }
index 5055c935838e974125529d814334d1b616057b66..ed8f02bf569974daeb14b91eeccd81e32d7f0a25 100644 (file)
@@ -8,11 +8,8 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
@@ -25,8 +22,11 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.yangtools.yang.model.api.Module;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Manages life cycle of {@link YangStoreSnapshot}.
@@ -76,8 +76,6 @@ public class NetconfOperationServiceImpl implements NetconfOperationService {
         capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
         // [RFC6241] 8.5.  Rollback-on-Error Capability
         capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
-        // [RFC6022] get-schema RPC. TODO: implement rest of the RFC
-        capabilities.add(new BasicCapability("urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04"));
 
         final Collection<Map.Entry<Module, String>> modulesAndContents = yangStoreSnapshot.getModuleMap().values();
         for (Map.Entry<Module, String> moduleAndContent : modulesAndContents) {
@@ -100,6 +98,11 @@ public class NetconfOperationServiceImpl implements NetconfOperationService {
             return capability;
         }
 
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.absent();
+        }
+
         @Override
         public Optional<String> getModuleName() {
             return Optional.absent();
@@ -114,6 +117,11 @@ public class NetconfOperationServiceImpl implements NetconfOperationService {
         public Optional<String> getCapabilitySchema() {
             return Optional.absent();
         }
+
+        @Override
+        public Optional<List<String>> getLocation() {
+            return Optional.absent();
+        }
     }
 
     private static class YangStoreCapability extends BasicCapability {
@@ -121,12 +129,14 @@ public class NetconfOperationServiceImpl implements NetconfOperationService {
         private final String content;
         private final String revision;
         private final String moduleName;
+        private final String moduleNamespace;
 
         public YangStoreCapability(Map.Entry<Module, String> moduleAndContent) {
             super(getAsString(moduleAndContent.getKey()));
             this.content = moduleAndContent.getValue();
             Module module = moduleAndContent.getKey();
             this.moduleName = module.getName();
+            this.moduleNamespace = module.getNamespace().toString();
             this.revision = Util.writeDate(module.getRevision());
         }
 
@@ -150,6 +160,11 @@ public class NetconfOperationServiceImpl implements NetconfOperationService {
             return Optional.of(moduleName);
         }
 
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.of(moduleNamespace);
+        }
+
         @Override
         public Optional<String> getRevision() {
             return Optional.of(revision);
index d91e38db33bf9206c96c18ba178dbfaa2ef115d7..35fa0428ec1cd60ed4a9e39415ce219c2a06ae9c 100644 (file)
@@ -132,10 +132,12 @@ public class NetconfMappingTest extends AbstractConfigTest {
         // check after edit
         commit();
         Element response = getConfigRunning();
+        System.err.println(XmlUtil.toString(response));
 
         checkBinaryLeafEdited(response);
         checkTypeConfigAttribute(response);
         checkTypedefs(response);
+        checkTestingDeps(response);
         checkEnum(response);
         checkBigDecimal(response);
 
@@ -163,11 +165,6 @@ public class NetconfMappingTest extends AbstractConfigTest {
         verifyNoMoreInteractions(netconfOperationRouter);
     }
 
-    private void checkBigDecimal(Element response) {
-        int size = response.getElementsByTagName("sleep-factor").getLength();
-        assertEquals(1, size);
-    }
-
     private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
             IOException {
         DefaultCloseSession closeOp = new DefaultCloseSession(NETCONF_SESSION_ID);
@@ -394,6 +391,17 @@ public class NetconfMappingTest extends AbstractConfigTest {
         fail("Enum attribute " + enumName + ":" + enumContent + " not present in " + XmlUtil.toString(response));
     }
 
+    private void checkTestingDeps(Element response) {
+        int testingDepsSize = response.getElementsByTagName("testing-deps").getLength();
+        assertEquals(2, testingDepsSize);
+    }
+
+    private void checkBigDecimal(Element response) {
+        int size = response.getElementsByTagName("sleep-factor").getLength();
+        assertEquals(1, size);
+    }
+
+
     private void checkTypeConfigAttribute(Element response) {
 
         XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data")
index 99b7ee60a2c51c8033c44e1195f78a93328b63c9..1c3ac7a455c4f80eb8a1607f1e942bb2c91f3977 100644 (file)
@@ -8,45 +8,22 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-import javax.annotation.concurrent.ThreadSafe;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServerConnection;
-import javax.management.Notification;
-import javax.management.NotificationListener;
-import javax.management.ObjectName;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
 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.opendaylight.controller.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
+
+import javax.annotation.concurrent.ThreadSafe;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServerConnection;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.regex.Pattern;
 
 /**
  * Responsible for listening for notifications from netconf containing latest
@@ -57,163 +34,27 @@ import org.xml.sax.SAXException;
 public class ConfigPersisterNotificationHandler implements NotificationListener, Closeable {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
-    private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
-    private static final int NETCONF_SEND_ATTEMPTS = 20;
-
-    private final InetSocketAddress address;
-    private final EventLoopGroup nettyThreadgroup;
-
-    private NetconfClientDispatcher netconfClientDispatcher;
-    private NetconfClient netconfClient;
-
-    private final Persister persister;
-    private final MBeanServerConnection mbeanServer;
-
-
-    private final ObjectName on = DefaultCommitOperationMXBean.objectName;
-
-    public static final long DEFAULT_TIMEOUT = 120000L;// 120 seconds until netconf must be stable
-    private final long timeout;
+    private final MBeanServerConnection mBeanServerConnection;
+    private final NetconfClient netconfClient;
+    private final PersisterAggregator persisterAggregator;
     private final Pattern ignoredMissingCapabilityRegex;
 
-    public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
-            MBeanServerConnection mbeanServer, Pattern ignoredMissingCapabilityRegex) {
-        this(persister, address, mbeanServer, DEFAULT_TIMEOUT, ignoredMissingCapabilityRegex);
-
-    }
-
-    public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
-            MBeanServerConnection mbeanServer, long timeout, Pattern ignoredMissingCapabilityRegex) {
-        this.persister = persister;
-        this.address = address;
-        this.mbeanServer = mbeanServer;
-        this.timeout = timeout;
-
-        this.nettyThreadgroup = new NioEventLoopGroup();
+    public ConfigPersisterNotificationHandler(MBeanServerConnection mBeanServerConnection, NetconfClient netconfClient,
+                                              PersisterAggregator persisterAggregator, Pattern ignoredMissingCapabilityRegex) {
+        this.mBeanServerConnection = mBeanServerConnection;
+        this.netconfClient = netconfClient;
+        this.persisterAggregator = persisterAggregator;
         this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex;
     }
 
-    public void init() throws InterruptedException {
-        Optional<ConfigSnapshotHolder> maybeConfig = loadLastConfig();
-
-        if (maybeConfig.isPresent()) {
-            logger.debug("Last config found {}", persister);
-            ConflictingVersionException lastException = null;
-            pushLastConfigWithRetries(maybeConfig, lastException);
-
-        } else {
-            // this ensures that netconf is initialized, this is first
-            // connection
-            // this means we can register as listener for commit
-            registerToNetconf(Collections.<String>emptySet());
-
-            logger.info("No last config provided by backend storage {}", persister);
-        }
+    public void init() {
         registerAsJMXListener();
     }
 
-    private void pushLastConfigWithRetries(Optional<ConfigSnapshotHolder> maybeConfig, ConflictingVersionException lastException) throws InterruptedException {
-        int maxAttempts = 30;
-        for(int i = 0 ; i < maxAttempts; i++) {
-            registerToNetconf(maybeConfig.get().getCapabilities());
-
-            final String configSnapshot = maybeConfig.get().getConfigSnapshot();
-            logger.trace("Pushing following xml to netconf {}", configSnapshot);
-            try {
-                pushLastConfig(XmlUtil.readXmlToElement(configSnapshot));
-                return;
-            } catch(ConflictingVersionException e) {
-                closeClientAndDispatcher(netconfClient, netconfClientDispatcher);
-                lastException = e;
-                Thread.sleep(1000);
-            } catch (SAXException | IOException e) {
-                throw new IllegalStateException("Unable to load last config", e);
-            }
-        }
-        throw new IllegalStateException("Failed to push configuration, maximum attempt count has been reached: "
-                + maxAttempts, lastException);
-    }
-
-    private synchronized long registerToNetconf(Set<String> expectedCaps) throws InterruptedException {
-
-        Set<String> currentCapabilities = Sets.newHashSet();
-
-        // TODO think about moving capability subset check to netconf client
-        // could be utilized by integration tests
-
-        long pollingStart = System.currentTimeMillis();
-        int delay = 5000;
-
-        int attempt = 0;
-
-        long deadline = pollingStart + timeout;
-        while (System.currentTimeMillis() < deadline) {
-            attempt++;
-            netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
-            try {
-                netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
-            } catch (IllegalStateException e) {
-                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
-                netconfClientDispatcher.close();
-                Thread.sleep(delay);
-                continue;
-            }
-            currentCapabilities = netconfClient.getCapabilities();
-
-            if (isSubset(currentCapabilities, expectedCaps)) {
-                logger.debug("Hello from netconf stable with {} capabilities", currentCapabilities);
-                long currentSessionId = netconfClient.getSessionId();
-                logger.info("Session id received from netconf server: {}", currentSessionId);
-                return currentSessionId;
-            }
-
-
-
-            logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, currentCapabilities);
-
-            closeClientAndDispatcher(netconfClient, netconfClientDispatcher);
-
-            Thread.sleep(delay);
-        }
-        Set<String> allNotFound = new HashSet<>(expectedCaps);
-        allNotFound.removeAll(currentCapabilities);
-        logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
-                allNotFound, expectedCaps ,currentCapabilities);
-        throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
-
-    }
-
-    private static void closeClientAndDispatcher(Closeable client, Closeable dispatcher) {
-        Exception fromClient = null;
-        try {
-            client.close();
-        } catch (Exception e) {
-            fromClient = e;
-        } finally {
-            try {
-                dispatcher.close();
-            } catch (Exception e) {
-                if (fromClient != null) {
-                    e.addSuppressed(fromClient);
-                }
-
-                throw new RuntimeException("Error closing temporary client ", e);
-            }
-        }
-    }
-
-    private boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
-        for (String exCap : expectedCaps) {
-            if (currentCapabilities.contains(exCap) == false)
-                return false;
-        }
-        return true;
-    }
-
     private void registerAsJMXListener() {
         logger.trace("Called registerAsJMXListener");
         try {
-            mbeanServer.addNotificationListener(on, this, null, null);
+            mBeanServerConnection.addNotificationListener(DefaultCommitOperationMXBean.objectName, this, null, null);
         } catch (InstanceNotFoundException | IOException e) {
             throw new RuntimeException("Cannot register as JMX listener to netconf", e);
         }
@@ -242,7 +83,7 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
 
     private void handleAfterCommitNotification(final CommitJMXNotification notification) {
         try {
-            persister.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
+            persisterAggregator.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
                     notification.getCapabilities(), ignoredMissingCapabilityRegex));
             logger.info("Configuration persisted successfully");
         } catch (IOException e) {
@@ -250,137 +91,21 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         }
     }
 
-    private Optional<ConfigSnapshotHolder> loadLastConfig() {
-        Optional<ConfigSnapshotHolder> maybeConfigElement;
-        try {
-            maybeConfigElement = persister.loadLastConfig();
-        } catch (IOException e) {
-            throw new RuntimeException("Unable to load configuration", e);
-        }
-        return maybeConfigElement;
-    }
-
-    private synchronized void pushLastConfig(Element xmlToBePersisted) throws ConflictingVersionException {
-        logger.info("Pushing last configuration to netconf");
-        StringBuilder response = new StringBuilder("editConfig response = {");
-
-
-        NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
-
-        // sending message to netconf
-        NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
-
-        XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
-        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
-        element = element.getOnlyChildElement();
-
-        checkIsOk(element, responseMessage);
-        response.append(XmlUtil.toString(responseMessage.getDocument()));
-        response.append("}");
-        responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
-
-        element = XmlElement.fromDomDocument(responseMessage.getDocument());
-        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
-        element = element.getOnlyChildElement();
-
-        checkIsOk(element, responseMessage);
-        response.append("commit response = {");
-        response.append(XmlUtil.toString(responseMessage.getDocument()));
-        response.append("}");
-        logger.info("Last configuration loaded successfully");
-        logger.trace("Detailed message {}", response);
-    }
-
-    static void checkIsOk(XmlElement element, NetconfMessage responseMessage) throws ConflictingVersionException {
-        if (element.getName().equals(XmlNetconfConstants.OK)) {
-            return;
-        }
-
-        if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) {
-            logger.warn("Can not load last configuration, operation failed");
-            // is it ConflictingVersionException ?
-            XPathExpression xPathExpression = XMLNetconfUtil.compileXPath("/netconf:rpc-reply/netconf:rpc-error/netconf:error-info/netconf:error");
-            String error = (String) XmlUtil.evaluateXPath(xPathExpression, element.getDomElement(), XPathConstants.STRING);
-            if (error!=null && error.contains(ConflictingVersionException.class.getCanonicalName())) {
-                throw new ConflictingVersionException(error);
-            }
-            throw new IllegalStateException("Can not load last configuration, operation failed: "
-                    + XmlUtil.toString(responseMessage.getDocument()));
-        }
-
-        logger.warn("Can not load last configuration. Operation failed.");
-        throw new IllegalStateException("Can not load last configuration. Operation failed: "
-                + XmlUtil.toString(responseMessage.getDocument()));
-    }
-
-    private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
-        try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
-            Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
-
-            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));
-            }
-            editConfigElement.appendChild(configWrapper.getDomElement());
-            return new NetconfMessage(doc);
-        } catch (IOException | SAXException e) {
-            throw new RuntimeException("Unable to parse message from resources " + editConfigResourcename, e);
-        }
-    }
-
-    private NetconfMessage getNetconfMessageFromResource(String resource) {
-        try (InputStream stream = getClass().getResourceAsStream(resource)) {
-            Preconditions.checkNotNull(stream, "Unable to load resource " + resource);
-            return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
-        } catch (SAXException | IOException e) {
-            throw new RuntimeException("Unable to parse message from resources " + resource, e);
-        }
-    }
-
     @Override
     public synchronized void close() {
-        // TODO persister is received from constructor, should not be closed
-        // here
-        try {
-            persister.close();
-        } catch (Exception e) {
-            logger.warn("Unable to close config persister {}", persister, e);
-        }
-
-        if (netconfClient != null) {
-            try {
-                netconfClient.close();
-            } catch (Exception e) {
-                logger.warn("Unable to close connection to netconf {}", netconfClient, e);
-            }
-        }
-
-        if (netconfClientDispatcher != null) {
-            try {
-                netconfClientDispatcher.close();
-            } catch (Exception e) {
-                logger.warn("Unable to close connection to netconf {}", netconfClientDispatcher, e);
-            }
-        }
-
-        try {
-            nettyThreadgroup.shutdownGracefully();
-        } catch (Exception e) {
-            logger.warn("Unable to close netconf client thread group {}", netconfClientDispatcher, e);
-        }
-
         // unregister from JMX
+        ObjectName on = DefaultCommitOperationMXBean.objectName;
         try {
-            if (mbeanServer.isRegistered(on)) {
-                mbeanServer.removeNotificationListener(on, this);
+            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;
+    }
+
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
new file mode 100644 (file)
index 0000000..044346e
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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.persist.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.netty.channel.EventLoopGroup;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import javax.annotation.concurrent.Immutable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Immutable
+public class ConfigPusher {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
+    private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
+    private static final int NETCONF_SEND_ATTEMPTS = 20;
+
+    private final InetSocketAddress address;
+    private final EventLoopGroup nettyThreadgroup;
+
+
+    public static final long DEFAULT_TIMEOUT = 120000L;// 120 seconds until netconf must be stable
+    private final long timeout;
+
+    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadgroup) {
+        this(address, DEFAULT_TIMEOUT, nettyThreadgroup);
+
+    }
+
+    public ConfigPusher(InetSocketAddress address, long timeout, EventLoopGroup nettyThreadgroup) {
+        this.address = address;
+        this.timeout = timeout;
+
+        this.nettyThreadgroup = nettyThreadgroup;
+    }
+
+    public synchronized NetconfClient init(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 {
+        NetconfClient netconfClient = makeNetconfConnection(Collections.<String>emptySet(), Optional.<NetconfClient>absent());
+        for (ConfigSnapshotHolder configSnapshotHolder: configs){
+            netconfClient = pushSnapshotWithRetries(configSnapshotHolder, Optional.of(netconfClient));
+        }
+        return netconfClient;
+    }
+
+    private synchronized NetconfClient pushSnapshotWithRetries(ConfigSnapshotHolder configSnapshotHolder,
+                                                               Optional<NetconfClient> oldClientForPossibleReuse)
+            throws InterruptedException {
+
+        ConflictingVersionException lastException = null;
+        int maxAttempts = 30;
+        for(int i = 0 ; i < maxAttempts; i++) {
+            NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities(), oldClientForPossibleReuse);
+            final String configSnapshot = configSnapshotHolder.getConfigSnapshot();
+            logger.trace("Pushing following xml to netconf {}", configSnapshot);
+            try {
+                pushLastConfig(configSnapshotHolder, netconfClient);
+                return netconfClient;
+            } catch(ConflictingVersionException e) {
+                Util.closeClientAndDispatcher(netconfClient);
+                lastException = e;
+                Thread.sleep(1000);
+            } catch (SAXException | IOException e) {
+                throw new IllegalStateException("Unable to load last config", e);
+            }
+        }
+        throw new IllegalStateException("Failed to push configuration, maximum attempt count has been reached: "
+                + maxAttempts, 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 oldClientForPossibleReuse if present, try to get expected capabilities from it before closing it and retrying with
+     *                                  new client connection.
+     * @return NetconfClient that has all required capabilities from server.
+     */
+    private synchronized NetconfClient makeNetconfConnection(Set<String> expectedCaps,
+                                                             Optional<NetconfClient> oldClientForPossibleReuse)
+            throws InterruptedException {
+
+        if (oldClientForPossibleReuse.isPresent()) {
+            NetconfClient oldClient = oldClientForPossibleReuse.get();
+            if (Util.isSubset(oldClient, expectedCaps)) {
+                return oldClient;
+            } else {
+                Util.closeClientAndDispatcher(oldClient);
+            }
+        }
+
+        // TODO think about moving capability subset check to netconf client
+        // could be utilized by integration tests
+
+        long pollingStart = System.currentTimeMillis();
+        int delay = 5000;
+
+        int attempt = 0;
+
+        long deadline = pollingStart + timeout;
+
+        Set<String> latestCapabilities = new HashSet<>();
+        while (System.currentTimeMillis() < deadline) {
+            attempt++;
+            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+            NetconfClient netconfClient;
+            try {
+                netconfClient = new NetconfClient(this.toString(), address, delay, netconfClientDispatcher);
+            } catch (IllegalStateException e) {
+                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
+                netconfClientDispatcher.close();
+                Thread.sleep(delay);
+                continue;
+            }
+            latestCapabilities = netconfClient.getCapabilities();
+            if (Util.isSubset(netconfClient, expectedCaps)) {
+                logger.debug("Hello from netconf stable with {} capabilities", latestCapabilities);
+                logger.info("Session id received from netconf server: {}", netconfClient.getClientSession());
+                return netconfClient;
+            }
+            logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, latestCapabilities);
+            Util.closeClientAndDispatcher(netconfClient);
+            Thread.sleep(delay);
+        }
+        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 {}",
+                allNotFound, expectedCaps, latestCapabilities);
+        throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
+    }
+
+
+    private synchronized void pushLastConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfClient netconfClient)
+            throws ConflictingVersionException, IOException, SAXException {
+
+        Element xmlToBePersisted = XmlUtil.readXmlToElement(configSnapshotHolder.getConfigSnapshot());
+        logger.info("Pushing last configuration to netconf: {}", configSnapshotHolder);
+        StringBuilder response = new StringBuilder("editConfig response = {");
+
+
+        NetconfMessage message = createEditConfigMessage(xmlToBePersisted, "/netconfOp/editConfig.xml");
+
+        // sending message to netconf
+        NetconfMessage responseMessage = netconfClient.sendMessage(message, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+
+        XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
+        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
+        element = element.getOnlyChildElement();
+
+        Util.checkIsOk(element, responseMessage);
+        response.append(XmlUtil.toString(responseMessage.getDocument()));
+        response.append("}");
+        responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"), NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+
+        element = XmlElement.fromDomDocument(responseMessage.getDocument());
+        Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
+        element = element.getOnlyChildElement();
+
+        Util.checkIsOk(element, responseMessage);
+        response.append("commit response = {");
+        response.append(XmlUtil.toString(responseMessage.getDocument()));
+        response.append("}");
+        logger.info("Last configuration loaded successfully");
+        logger.trace("Detailed message {}", response);
+    }
+
+    private static NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
+        try (InputStream stream = ConfigPersisterNotificationHandler.class.getResourceAsStream(editConfigResourcename)) {
+            Preconditions.checkNotNull(stream, "Unable to load resource " + editConfigResourcename);
+
+            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));
+            }
+            editConfigElement.appendChild(configWrapper.getDomElement());
+            return new NetconfMessage(doc);
+        } catch (IOException | SAXException e) {
+            throw new RuntimeException("Unable to parse message from resources " + editConfigResourcename, e);
+        }
+    }
+
+    private static NetconfMessage getNetconfMessageFromResource(String resource) {
+        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) {
+            throw new RuntimeException("Unable to parse message from resources " + resource, e);
+        }
+    }
+}
index b37c1457c330ee73467e48950144bf3ee237ccbc..27f930990dd22149e17fb8092a2ae30bbaa93a6e 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
@@ -17,6 +16,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 
 public class NoOpStorageAdapter implements StorageAdapter, Persister {
     private static final Logger logger = LoggerFactory.getLogger(NoOpStorageAdapter.class);
@@ -33,9 +34,9 @@ public class NoOpStorageAdapter implements StorageAdapter, Persister {
     }
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         logger.debug("loadLastConfig called");
-        return Optional.absent();
+        return Collections.emptyList();
     }
 
     @Override
index e109ebec887b8e3c2a1579e5e2292fc970b25f1e..7e9dce67bd78586459b8d8d2c40e248b392ecf01 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.netconf.persist.impl;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.StorageAdapter;
@@ -20,6 +19,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
 
@@ -48,7 +48,7 @@ import java.util.ListIterator;
  </pre>
  * During server startup {@link ConfigPersisterNotificationHandler} requests last snapshot from underlying storages.
  * Each storage can respond by giving snapshot or absent response.
- * The {@link #loadLastConfig()} will search for first non-absent response from storages ordered backwards as user
+ * The {@link #loadLastConfigs()} will search for first non-absent response from storages ordered backwards as user
  * specified (first '3', then '2').
  *
  * When a commit notification is received, '2' will be omitted because readonly flag is set to true, so
@@ -154,19 +154,29 @@ public final class PersisterAggregator implements Persister {
         }
     }
 
+    /**
+     * @return last non-empty result from input persisters
+     */
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs()  {
         // iterate in reverse order
         ListIterator<PersisterWithConfiguration> li = persisterWithConfigurations.listIterator(persisterWithConfigurations.size());
         while(li.hasPrevious()) {
             PersisterWithConfiguration persisterWithConfiguration = li.previous();
-            Optional<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterWithConfiguration.storage.loadLastConfig();
-            if (configSnapshotHolderOptional.isPresent()) {
-                return configSnapshotHolderOptional;
+            List<ConfigSnapshotHolder> configs = null;
+            try {
+                configs = persisterWithConfiguration.storage.loadLastConfigs();
+            } catch (IOException e) {
+                throw new RuntimeException("Error while calling loadLastConfig on " +  persisterWithConfiguration, e);
+            }
+            if (configs.isEmpty() == false) {
+                logger.debug("Found non empty configs using {}:{}", persisterWithConfiguration, configs);
+                return configs;
             }
         }
         // no storage had an answer
-        return Optional.absent();
+        logger.debug("No non-empty list of configuration snapshots found");
+        return Collections.emptyList();
     }
 
     @VisibleForTesting
index b17309123c8081ce081b178539d66ea68bfdb116..811ba38c10068d470492a93073a656f6b0c42f79 100644 (file)
@@ -8,24 +8,79 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import java.util.Set;
 
 public final class Util {
+    private static final Logger logger = LoggerFactory.getLogger(Util.class);
+
+
+    public static boolean isSubset(NetconfClient netconfClient, Set<String> expectedCaps) {
+        return isSubset(netconfClient.getCapabilities(), expectedCaps);
+
+    }
+
+    private static boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
+        for (String exCap : expectedCaps) {
+            if (currentCapabilities.contains(exCap) == false)
+                return false;
+        }
+        return true;
+    }
+
+
+    // TODO: check if closing in correct order
+    public static void closeClientAndDispatcher(NetconfClient client) {
+        NetconfClientDispatcher dispatcher = client.getNetconfClientDispatcher();
+        Exception fromClient = null;
+        try {
+            client.close();
+        } catch (Exception e) {
+            fromClient = e;
+        } finally {
+            try {
+                dispatcher.close();
+            } catch (Exception e) {
+                if (fromClient != null) {
+                    e.addSuppressed(fromClient);
+                }
+                throw new RuntimeException("Error closing temporary client ", e);
+            }
+        }
+    }
 
-    public static ScheduledExecutorService getExecutorServiceWithThreadName(final String threadNamePrefix,
-            int threadCount) {
-        return Executors.newScheduledThreadPool(threadCount, new ThreadFactory() {
 
-            private int i = 1;
+    public static void checkIsOk(XmlElement element, NetconfMessage responseMessage) throws ConflictingVersionException {
+        if (element.getName().equals(XmlNetconfConstants.OK)) {
+            return;
+        }
 
-            @Override
-            public Thread newThread(Runnable r) {
-                Thread thread = new Thread(r);
-                thread.setName(threadNamePrefix + ":" + i++);
-                return thread;
+        if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) {
+            logger.warn("Can not load last configuration, operation failed");
+            // is it ConflictingVersionException ?
+            XPathExpression xPathExpression = XMLNetconfUtil.compileXPath("/netconf:rpc-reply/netconf:rpc-error/netconf:error-info/netconf:error");
+            String error = (String) XmlUtil.evaluateXPath(xPathExpression, element.getDomElement(), XPathConstants.STRING);
+            if (error!=null && error.contains(ConflictingVersionException.class.getCanonicalName())) {
+                throw new ConflictingVersionException(error);
             }
-        });
+            throw new IllegalStateException("Can not load last configuration, operation failed: "
+                    + XmlUtil.toString(responseMessage.getDocument()));
+        }
+
+        logger.warn("Can not load last configuration. Operation failed.");
+        throw new IllegalStateException("Can not load last configuration. Operation failed: "
+                + XmlUtil.toString(responseMessage.getDocument()));
     }
 }
index e7916c2d5f3d041ee315e03335586d533c76206e..656091115c8907aa5de61394e1a6a6f9da516317 100644 (file)
@@ -8,8 +8,13 @@
 
 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;
@@ -28,14 +33,19 @@ public class ConfigPersisterActivator implements BundleActivator {
     private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
     private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
 
-    private ConfigPersisterNotificationHandler configPersisterNotificationHandler;
+    public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
 
-    private Thread initializationThread;
+    public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
 
-    public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
-    public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX =  "storageAdapterClass";
     public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0";
 
+
+    private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
+    private volatile NetconfClient netconfClient;
+    private Thread initializationThread;
+    private EventLoopGroup nettyThreadgroup;
+    private PersisterAggregator persisterAggregator;
+
     @Override
     public void start(final BundleContext context) throws Exception {
         logger.debug("ConfigPersister starting");
@@ -49,20 +59,24 @@ public class ConfigPersisterActivator implements BundleActivator {
         } else {
             regex = DEFAULT_IGNORED_REGEX;
         }
-        Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
-        PersisterAggregator persister = PersisterAggregator.createFromProperties(propertiesProvider);
+        final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
+        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);
 
-        InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
-                "Netconf is not configured, persister is not operational",true);
-        configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(persister, address,
-                platformMBeanServer, ignoredMissingCapabilityRegex);
 
         // offload initialization to another thread in order to stop blocking activator
         Runnable initializationRunnable = new Runnable() {
             @Override
             public void run() {
                 try {
-                    configPersisterNotificationHandler.init();
+                    netconfClient = configPusher.init(persisterAggregator.loadLastConfigs());
+                    jmxNotificationHandler = new ConfigPersisterNotificationHandler(
+                            platformMBeanServer, netconfClient, persisterAggregator,
+                            ignoredMissingCapabilityRegex);
+                    jmxNotificationHandler.init();
                 } catch (InterruptedException e) {
                     logger.info("Interrupted while waiting for netconf connection");
                 }
@@ -75,6 +89,18 @@ public class ConfigPersisterActivator implements BundleActivator {
     @Override
     public void stop(BundleContext context) throws Exception {
         initializationThread.interrupt();
-        configPersisterNotificationHandler.close();
+        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();
+        persisterAggregator.close();
     }
 }
index 4e34591284e78e23e4b84f0553aea90c53792295..b1f783343d5bfe5a93793e045755c0254c68f537 100644 (file)
@@ -1,5 +1,5 @@
-<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
-    <capabilities>
-        <capability>urn:ietf:params:netconf:base:1.0</capability>
-    </capabilities>
-</hello>
+    <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+        <capabilities>
+            <capability>urn:ietf:params:netconf:base:1.0</capability>
+        </capabilities>
+    </hello>
index 6c45c9c0119073fd4ff8d64869ed6a7068181090..a124d85b91c7deea3a027d1726fddba01d74258c 100644 (file)
@@ -24,7 +24,7 @@ public class ConfigPersisterNotificationHandlerTest {
     public void testConflictingVersionDetection() throws Exception {
         Document document = XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/conflictingVersionResponse.xml"));
         try{
-            ConfigPersisterNotificationHandler.checkIsOk(XmlElement.fromDomDocument(document).getOnlyChildElement(), new NetconfMessage(document));
+            Util.checkIsOk(XmlElement.fromDomDocument(document).getOnlyChildElement(), new NetconfMessage(document));
             fail();
         }catch(ConflictingVersionException e){
             assertThat(e.getMessage(), containsString("Optimistic lock failed. Expected parent version 21, was 18"));
index 7a11b9cd6fa092709239cccca223c55d69d533d4..e824b588324e25a232ff03f6faef2f54be7f3839 100644 (file)
@@ -7,13 +7,14 @@
  */
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
 import org.opendaylight.controller.config.persist.api.StorageAdapter;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 
 public class DummyAdapter implements StorageAdapter, Persister {
 
@@ -27,9 +28,9 @@ public class DummyAdapter implements StorageAdapter, Persister {
     static int load = 0;
 
     @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
         load++;
-        return Optional.absent();
+        return Collections.emptyList();
     }
 
     static int props = 0;
index d9fa7ba4d82dbfa931106d93389d83837f105daf..227018bf5b8761e82b88760cdd3dc8a4a6e23705 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
@@ -18,14 +17,14 @@ import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderB
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Properties;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.junit.matchers.JUnitMatchers.containsString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -79,9 +78,9 @@ public class PersisterAggregatorTest {
         assertFalse(persister.isReadOnly());
 
         persisterAggregator.persistConfig(null);
-        persisterAggregator.loadLastConfig();
+        persisterAggregator.loadLastConfigs();
         persisterAggregator.persistConfig(null);
-        persisterAggregator.loadLastConfig();
+        persisterAggregator.loadLastConfigs();
 
         assertEquals(2, DummyAdapter.persist);
         assertEquals(2, DummyAdapter.load);
@@ -110,29 +109,41 @@ public class PersisterAggregatorTest {
         }
     }
 
+    private ConfigSnapshotHolder mockHolder(String name){
+        ConfigSnapshotHolder result = mock(ConfigSnapshotHolder.class);
+        doReturn("mock:" + name).when(result).toString();
+        return result;
+    }
+
+    private Persister mockPersister(String name){
+        Persister result = mock(Persister.class);
+        doReturn("mock:" + name).when(result).toString();
+        return result;
+    }
+
     @Test
     public void loadLastConfig() throws Exception {
         List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
         PersisterWithConfiguration first = new PersisterWithConfiguration(mock(Persister.class), false);
 
-        ConfigSnapshotHolder ignored = mock(ConfigSnapshotHolder.class);
-        doReturn(Optional.of(ignored)).when(first.getStorage()).loadLastConfig(); // should be ignored
+        ConfigSnapshotHolder ignored = mockHolder("ignored");
+        doReturn(Arrays.asList(ignored)).when(first.getStorage()).loadLastConfigs(); // should be ignored
 
-        ConfigSnapshotHolder used = mock(ConfigSnapshotHolder.class);
-        PersisterWithConfiguration second = new PersisterWithConfiguration(mock(Persister.class), false);
-        doReturn(Optional.of(used)).when(second.getStorage()).loadLastConfig(); // should be used
 
-        PersisterWithConfiguration third = new PersisterWithConfiguration(mock(Persister.class), false);
-        doReturn(Optional.absent()).when(third.getStorage()).loadLastConfig();
+        ConfigSnapshotHolder used = mockHolder("used");
+        PersisterWithConfiguration second = new PersisterWithConfiguration(mockPersister("p1"), false);
+        doReturn(Arrays.asList(used)).when(second.getStorage()).loadLastConfigs(); // should be used
+
+        PersisterWithConfiguration third = new PersisterWithConfiguration(mockPersister("p2"), false);
+        doReturn(Arrays.asList()).when(third.getStorage()).loadLastConfigs();
 
         persisterWithConfigurations.add(first);
         persisterWithConfigurations.add(second);
         persisterWithConfigurations.add(third);
 
         PersisterAggregator persisterAggregator = new PersisterAggregator(persisterWithConfigurations);
-        Optional<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterAggregator.loadLastConfig();
-        assertTrue(configSnapshotHolderOptional.isPresent());
-        assertEquals(used, configSnapshotHolderOptional.get());
+        List<ConfigSnapshotHolder> configSnapshotHolderOptional = persisterAggregator.loadLastConfigs();
+        assertEquals(1, configSnapshotHolderOptional.size());
+        assertEquals(used, configSnapshotHolderOptional.get(0));
     }
-
 }
diff --git a/opendaylight/netconf/ietf-netconf-monitoring/pom.xml b/opendaylight/netconf/ietf-netconf-monitoring/pom.xml
new file mode 100644 (file)
index 0000000..f564c8c
--- /dev/null
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>netconf-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>ietf-netconf-monitoring</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-yang-types</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <plugins>
+            <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>
+                                        target/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.binding.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>target/generated-sources/sal</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            com.google.common.collect,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
+                            org.opendaylight.yangtools.yang.binding,
+                            org.opendaylight.yangtools.yang.common,
+                        </Import-Package>
+                        <Export-Package>
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.*
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/opendaylight/netconf/ietf-netconf-monitoring/src/main/yang/ietf-netconf-monitoring.yang b/opendaylight/netconf/ietf-netconf-monitoring/src/main/yang/ietf-netconf-monitoring.yang
new file mode 100644 (file)
index 0000000..391edd0
--- /dev/null
@@ -0,0 +1,593 @@
+module ietf-netconf-monitoring {
+
+    yang-version 1;
+
+    namespace
+      "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
+
+    prefix ncm;
+
+    import ietf-yang-types {
+      prefix yang;
+    }
+    import ietf-inet-types {
+      prefix inet;
+    }
+
+    organization
+      "IETF NETCONF (Network Configuration) Working Group";
+
+    contact
+      "WG Web:   <http://tools.ietf.org/wg/netconf/>
+     WG List:  <mailto:netconf@ietf.org>
+
+     WG Chair: Mehmet Ersue
+               <mailto:mehmet.ersue@nsn.com>
+
+     WG Chair: Bert Wijnen
+               <mailto:bertietf@bwijnen.net>
+
+     Editor:   Mark Scott
+               <mailto:mark.scott@ericsson.com>
+
+     Editor:   Martin Bjorklund
+               <mailto:mbj@tail-f.com>";
+
+    description
+      "NETCONF Monitoring Module.
+     All elements in this module are read-only.
+
+     Copyright (c) 2010 IETF Trust and the persons identified as
+     authors of the code. All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD
+     License set forth in Section 4.c of the IETF Trust's
+     Legal Provisions Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 6022; see
+     the RFC itself for full legal notices.";
+
+    revision "2010-10-04" {
+      description "Initial revision.";
+      reference
+        "RFC 6022: YANG Module for NETCONF Monitoring";
+
+    }
+
+
+    typedef netconf-datastore-type {
+      type enumeration {
+        enum "running" {
+          value 0;
+        }
+        enum "candidate" {
+          value 1;
+        }
+        enum "startup" {
+          value 2;
+        }
+      }
+      description
+        "Enumeration of possible NETCONF datastore types.";
+      reference
+        "RFC 4741: NETCONF Configuration Protocol";
+
+    }
+
+    identity transport {
+      description
+        "Base identity for NETCONF transport types.";
+    }
+
+    identity netconf-ssh {
+      base transport;
+      description
+        "NETCONF over Secure Shell (SSH).";
+      reference
+        "RFC 4742: Using the NETCONF Configuration Protocol
+                 over Secure SHell (SSH)";
+
+    }
+
+    identity netconf-soap-over-beep {
+      base transport;
+      description
+        "NETCONF over Simple Object Access Protocol (SOAP) over
+       Blocks Extensible Exchange Protocol (BEEP).";
+      reference
+        "RFC 4743: Using NETCONF over the Simple Object
+                 Access Protocol (SOAP)";
+
+    }
+
+    identity netconf-soap-over-https {
+      base transport;
+      description
+        "NETCONF over Simple Object Access Protocol (SOAP)
+      over Hypertext Transfer Protocol Secure (HTTPS).";
+      reference
+        "RFC 4743: Using NETCONF over the Simple Object
+                 Access Protocol (SOAP)";
+
+    }
+
+    identity netconf-beep {
+      base transport;
+      description
+        "NETCONF over Blocks Extensible Exchange Protocol (BEEP).";
+      reference
+        "RFC 4744: Using the NETCONF Protocol over the
+                 Blocks Extensible Exchange Protocol (BEEP)";
+
+    }
+
+    identity netconf-tls {
+      base transport;
+      description
+        "NETCONF over Transport Layer Security (TLS).";
+      reference
+        "RFC 5539: NETCONF over Transport Layer Security (TLS)";
+
+    }
+
+    identity schema-format {
+      description
+        "Base identity for data model schema languages.";
+    }
+
+    identity xsd {
+      base schema-format;
+      description
+        "W3C XML Schema Definition.";
+      reference
+        "W3C REC REC-xmlschema-1-20041028:
+          XML Schema Part 1: Structures";
+
+    }
+
+    identity yang {
+      base schema-format;
+      description
+        "The YANG data modeling language for NETCONF.";
+      reference
+        "RFC 6020:  YANG - A Data Modeling Language for the
+                  Network Configuration Protocol (NETCONF)";
+
+    }
+
+    identity yin {
+      base schema-format;
+      description "The YIN syntax for YANG.";
+      reference
+        "RFC 6020:  YANG - A Data Modeling Language for the
+                  Network Configuration Protocol (NETCONF)";
+
+    }
+
+    identity rng {
+      base schema-format;
+      description
+        "Regular Language for XML Next Generation (RELAX NG).";
+      reference
+        "ISO/IEC 19757-2:2008: RELAX NG";
+
+    }
+
+    identity rnc {
+      base schema-format;
+      description "Relax NG Compact Syntax";
+      reference
+        "ISO/IEC 19757-2:2008: RELAX NG";
+
+    }
+
+    grouping common-counters {
+      description
+        "Counters that exist both per session, and also globally,
+       accumulated from all sessions.";
+      leaf in-rpcs {
+        type yang:zero-based-counter32;
+        description
+          "Number of correct <rpc> messages received.";
+      }
+
+      leaf in-bad-rpcs {
+        type yang:zero-based-counter32;
+        description
+          "Number of messages received when an <rpc> message was expected,
+         that were not correct <rpc> messages.  This includes XML parse
+         errors and errors on the rpc layer.";
+      }
+
+      leaf out-rpc-errors {
+        type yang:zero-based-counter32;
+        description
+          "Number of <rpc-reply> messages sent that contained an
+         <rpc-error> element.";
+      }
+
+      leaf out-notifications {
+        type yang:zero-based-counter32;
+        description
+          "Number of <notification> messages sent.";
+      }
+    }  // grouping common-counters
+
+    container netconf-state {
+      config false;
+      description
+        "The netconf-state container is the root of the monitoring
+       data model.";
+      container capabilities {
+        description
+          "Contains the list of NETCONF capabilities supported by the
+         server.";
+        leaf-list capability {
+          type inet:uri;
+          description
+            "List of NETCONF capabilities supported by the server.";
+        }
+      }  // container capabilities
+
+      container datastores {
+        description
+          "Contains the list of NETCONF configuration datastores.";
+        list datastore {
+          key "name";
+          description
+            "List of NETCONF configuration datastores supported by
+           the NETCONF server and related information.";
+          leaf name {
+            type netconf-datastore-type;
+            description
+              "Name of the datastore associated with this list entry.";
+          }
+
+          container locks {
+            presence
+              "This container is present only if the datastore
+             is locked.";
+            description
+              "The NETCONF <lock> and <partial-lock> operations allow
+             a client to lock specific resources in a datastore.  The
+             NETCONF server will prevent changes to the locked
+             resources by all sessions except the one that acquired
+             the lock(s).
+
+             Monitoring information is provided for each datastore
+             entry including details such as the session that acquired
+             the lock, the type of lock (global or partial) and the
+             list of locked resources.  Multiple locks per datastore
+             are supported.";
+            grouping lock-info {
+              description
+                "Lock related parameters, common to both global and
+               partial locks.";
+              leaf locked-by-session {
+                type uint32;
+                mandatory true;
+                description
+                  "The session ID of the session that has locked
+                 this resource.  Both a global lock and a partial
+                 lock MUST contain the NETCONF session-id.
+
+                 If the lock is held by a session that is not managed
+                 by the NETCONF server (e.g., a CLI session), a session
+                 id of 0 (zero) is reported.";
+                reference
+                  "RFC 4741: NETCONF Configuration Protocol";
+
+              }
+
+              leaf locked-time {
+                type yang:date-and-time;
+                mandatory true;
+                description
+                  "The date and time of when the resource was
+                 locked.";
+              }
+            }  // grouping lock-info
+            choice lock-type {
+              description
+                "Indicates if a global lock or a set of partial locks
+               are set.";
+              container global-lock {
+                description
+                  "Present if the global lock is set.";
+                uses lock-info;
+              }  // container global-lock
+              list partial-lock {
+                key "lock-id";
+                description
+                  "List of partial locks.";
+                reference
+                  "RFC 5717: Partial Lock Remote Procedure Call (RPC) for
+                         NETCONF";
+
+                leaf lock-id {
+                  type uint32;
+                  description
+                    "This is the lock id returned in the <partial-lock>
+                   response.";
+                }
+
+                uses lock-info;
+
+                leaf-list select {
+                  type yang:xpath1.0;
+                  min-elements 1;
+                  description
+                    "The xpath expression that was used to request
+                   the lock.  The select expression indicates the
+                   original intended scope of the lock.";
+                }
+
+                leaf-list locked-node {
+                  type instance-identifier;
+                  description
+                    "The list of instance-identifiers (i.e., the
+                   locked nodes).
+
+                   The scope of the partial lock is defined by the list
+                   of locked nodes.";
+                }
+              }  // list partial-lock
+            }  // choice lock-type
+          }  // container locks
+        }  // list datastore
+      }  // container datastores
+
+      container schemas {
+        description
+          "Contains the list of data model schemas supported by the
+         server.";
+        list schema {
+          key "identifier version format";
+          description
+            "List of data model schemas supported by the server.";
+          leaf identifier {
+            type string;
+            description
+              "Identifier to uniquely reference the schema.  The
+             identifier is used in the <get-schema> operation and may
+             be used for other purposes such as file retrieval.
+
+             For modeling languages that support or require a data
+             model name (e.g., YANG module name) the identifier MUST
+             match that name.  For YANG data models, the identifier is
+             the name of the module or submodule.  In other cases, an
+             identifier such as a filename MAY be used instead.";
+          }
+
+          leaf version {
+            type string;
+            description
+              "Version of the schema supported.  Multiple versions MAY be
+             supported simultaneously by a NETCONF server.  Each
+             version MUST be reported individually in the schema list,
+             i.e., with same identifier, possibly different location,
+             but different version.
+
+             For YANG data models, version is the value of the most
+             recent YANG 'revision' statement in the module or
+             submodule, or the empty string if no 'revision' statement
+             is present.";
+          }
+
+          leaf format {
+            type identityref {
+              base schema-format;
+            }
+            description
+              "The data modeling language the schema is written
+             in (currently xsd, yang, yin, rng, or rnc).
+             For YANG data models, 'yang' format MUST be supported and
+             'yin' format MAY also be provided.";
+          }
+
+          leaf namespace {
+            type inet:uri;
+            mandatory true;
+            description
+              "The XML namespace defined by the data model.
+
+             For YANG data models, this is the module's namespace.
+             If the list entry describes a submodule, this field
+             contains the namespace of the module to which the
+             submodule belongs.";
+          }
+
+          leaf-list location {
+            type union {
+              type enumeration {
+                enum "NETCONF" {
+                  value 0;
+                }
+              }
+              type inet:uri;
+            }
+            description
+              "One or more locations from which the schema can be
+             retrieved.  This list SHOULD contain at least one
+             entry per schema.
+
+             A schema entry may be located on a remote file system
+             (e.g., reference to file system for ftp retrieval) or
+             retrieved directly from a server supporting the
+             <get-schema> operation (denoted by the value 'NETCONF').";
+          }
+        }  // list schema
+      }  // container schemas
+
+      container sessions {
+        description
+          "The sessions container includes session-specific data for
+         NETCONF management sessions.  The session list MUST include
+         all currently active NETCONF sessions.";
+        list session {
+          key "session-id";
+          description
+            "All NETCONF sessions managed by the NETCONF server
+           MUST be reported in this list.";
+          leaf session-id {
+            type uint32 {
+              range "1..max";
+            }
+            description
+              "Unique identifier for the session.  This value is the
+             NETCONF session identifier, as defined in RFC 4741.";
+            reference
+              "RFC 4741: NETCONF Configuration Protocol";
+
+          }
+
+          leaf transport {
+            type identityref {
+              base transport;
+            }
+            mandatory true;
+            description
+              "Identifies the transport for each session, e.g.,
+            'netconf-ssh', 'netconf-soap', etc.";
+          }
+
+          leaf username {
+            type string;
+            mandatory true;
+            description
+              "The username is the client identity that was authenticated
+            by the NETCONF transport protocol.  The algorithm used to
+            derive the username is NETCONF transport protocol specific
+            and in addition specific to the authentication mechanism
+            used by the NETCONF transport protocol.";
+          }
+
+          leaf source-host {
+            type inet:host;
+            description
+              "Host identifier of the NETCONF client.  The value
+             returned is implementation specific (e.g., hostname,
+             IPv4 address, IPv6 address)";
+          }
+
+          leaf login-time {
+            type yang:date-and-time;
+            mandatory true;
+            description
+              "Time at the server at which the session was established.";
+          }
+
+          uses common-counters {
+            description
+              "Per-session counters.  Zero based with following reset
+             behaviour:
+               - at start of a session
+               - when max value is reached";
+          }
+        }  // list session
+      }  // container sessions
+
+      container statistics {
+        description
+          "Statistical data pertaining to the NETCONF server.";
+        leaf netconf-start-time {
+          type yang:date-and-time;
+          description
+            "Date and time at which the management subsystem was
+           started.";
+        }
+
+        leaf in-bad-hellos {
+          type yang:zero-based-counter32;
+          description
+            "Number of sessions silently dropped because an
+          invalid <hello> message was received.  This includes <hello>
+          messages with a 'session-id' attribute, bad namespace, and
+          bad capability declarations.";
+        }
+
+        leaf in-sessions {
+          type yang:zero-based-counter32;
+          description
+            "Number of sessions started.  This counter is incremented
+           when a <hello> message with a <session-id> is sent.
+
+          'in-sessions' - 'in-bad-hellos' =
+              'number of correctly started netconf sessions'";
+        }
+
+        leaf dropped-sessions {
+          type yang:zero-based-counter32;
+          description
+            "Number of sessions that were abnormally terminated, e.g.,
+           due to idle timeout or transport close.  This counter is not
+           incremented when a session is properly closed by a
+           <close-session> operation, or killed by a <kill-session>
+           operation.";
+        }
+
+        uses common-counters {
+          description
+            "Global counters, accumulated from all sessions.
+           Zero based with following reset behaviour:
+             - re-initialization of NETCONF server
+             - when max value is reached";
+        }
+      }  // container statistics
+    }  // container netconf-state
+
+    rpc get-schema {
+      description
+        "This operation is used to retrieve a schema from the
+       NETCONF server.
+
+       Positive Response:
+         The NETCONF server returns the requested schema.
+
+       Negative Response:
+         If requested schema does not exist, the <error-tag> is
+         'invalid-value'.
+
+         If more than one schema matches the requested parameters, the
+         <error-tag> is 'operation-failed', and <error-app-tag> is
+         'data-not-unique'.";
+      input {
+        leaf identifier {
+          type string;
+          mandatory true;
+          description
+            "Identifier for the schema list entry.";
+        }
+
+        leaf version {
+          type string;
+          description
+            "Version of the schema requested.  If this parameter is not
+           present, and more than one version of the schema exists on
+           the server, a 'data-not-unique' error is returned, as
+           described above.";
+        }
+
+        leaf format {
+          type identityref {
+            base schema-format;
+          }
+          description
+            "The data modeling language of the schema.  If this
+            parameter is not present, and more than one formats of
+            the schema exists on the server, a 'data-not-unique' error
+            is returned, as described above.";
+        }
+      }
+
+      output {
+        anyxml data {
+          description
+            "Contains the schema content.";
+        }
+      }
+    }  // rpc get-schema
+} // module
\ No newline at end of file
index 0e9b421229873365a9fe08785f41f1b93ff6834e..0fce4748a40af53113d865492dd1f6ada93ce19a 100644 (file)
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>config-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-yang-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ietf-netconf-monitoring</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.opendaylight.bgpcep</groupId>
             <artifactId>framework</artifactId>
                             io.netty.channel,
                             io.netty.util.concurrent,
                             org.w3c.dom,
-                            org.slf4j
+                            org.slf4j,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
+                            com.google.common.base,
                         </Import-Package>
                         <Export-Package>
                             org.opendaylight.controller.netconf.api,
                             org.opendaylight.controller.netconf.api.jmx,
+                            org.opendaylight.controller.netconf.api.monitoring,
                         </Export-Package>
                     </instructions>
                 </configuration>
index e5a9e18576afbca754a3b111b4574ae54f9ff64f..a0fddd79f2f0fcff8afced3ab91fcf21aeeea44d 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.netconf.api;
 
+import com.google.common.base.Optional;
 import org.w3c.dom.Document;
 
 /**
@@ -20,11 +21,22 @@ public final class NetconfMessage {
 
     private final Document doc;
 
+    private String additionalHeader;
+
     public NetconfMessage(final Document doc) {
+        this(doc, null);
+    }
+
+    public NetconfMessage(Document doc, String additionalHeader) {
         this.doc = doc;
+        this.additionalHeader = additionalHeader;
     }
 
     public Document getDocument() {
         return this.doc;
     }
+
+    public Optional<String> getAdditionalHeader() {
+        return additionalHeader== null ? Optional.<String>absent() : Optional.of(additionalHeader);
+    }
 }
index 17330b7babde5ce12030568ffca5d12207edb946..1e14bfdba285ec0e8f68f3b0b363abe2e370c66b 100644 (file)
@@ -52,6 +52,7 @@ public abstract class NetconfSession extends AbstractProtocolSession<NetconfMess
     @Override
     public void close() {
         channel.close();
+        up = false;
         sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed"));
     }
 
diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/NetconfManagementSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/NetconfManagementSession.java
new file mode 100644 (file)
index 0000000..3c7db49
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.api.monitoring;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+
+public interface NetconfManagementSession {
+
+    Session toManagementSession();
+}
diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/NetconfMonitoringService.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/NetconfMonitoringService.java
new file mode 100644 (file)
index 0000000..51eea93
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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.api.monitoring;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
+
+public interface NetconfMonitoringService {
+
+    Sessions getSessions();
+
+    Schemas getSchemas();
+}
index d95977492a9206fb0ff05d4e6229810b08dcda9a..d644cddff4855afe0a6e87b399a81d9eb5f5b152 100644 (file)
@@ -100,6 +100,10 @@ public class NetconfClient implements Closeable {
         clientSession.close();
     }
 
+    public NetconfClientDispatcher getNetconfClientDispatcher() {
+        return dispatch;
+    }
+
     private static ReconnectStrategy getReconnectStrategy(int connectionAttempts, int attemptMsTimeout) {
         return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
                 Long.valueOf(connectionAttempts), null);
index c2c8d38b9a8daa08804a686e75106f4a86a60a58..c57487f70b8d12779d88b68c7e20fe879739790a 100644 (file)
@@ -31,4 +31,5 @@ public class NetconfClientSession extends NetconfSession {
     public Collection<String> getServerCapabilities() {
         return capabilities;
     }
+
 }
index 17a55c52bcbf7b1a6dd13a9afcbaa61a382d9388..3340dde883f09cfb077c6c1dcc6b6ea1b0ca8592 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.collect.Collections2;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
 import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
@@ -66,7 +67,8 @@ public class NetconfClientSessionNegotiator extends
     }
 
     @Override
-    protected NetconfClientSession getSession(SessionListener sessionListener, Channel channel, Document doc) {
-        return new NetconfClientSession(sessionListener, channel, extractSessionId(doc), getCapabilities(doc));
+    protected NetconfClientSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) {
+        return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()),
+                getCapabilities(message.getDocument()));
     }
 }
index f1e3f891ee3ff70bda9cfd9fefcc73c714a824e3..e073aaca8d039dddf4f6c976dcbe1e30de1b4dd7 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ietf-netconf-monitoring</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-util</artifactId>
             <artifactId>netconf-mapping-api</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.opendaylight.bgpcep</groupId>
             <artifactId>util</artifactId>
                             io.netty.buffer,
                             io.netty.handler.codec,
                             io.netty.channel.nio,
+                            javax.annotation,
                             javax.management,
                             javax.net.ssl,
                             javax.xml.namespace,
                             org.w3c.dom,
                             org.xml.sax,
                             org.opendaylight.controller.netconf.util.messages,
-                            com.siemens.ct.exi.exceptions
+                            com.siemens.ct.exi.exceptions,
+                            io.netty.util.internal,
+                            org.opendaylight.controller.netconf.api.monitoring,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
                         </Import-Package>
                     </instructions>
                 </configuration>
index a4d7e747234ce07804a1405ff4f96ff31ecd35e5..b6921794296e3f04d02d6e36ef45762a8888ecec 100644 (file)
 
 package org.opendaylight.controller.netconf.impl;
 
+import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
-
 import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.SessionBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.SessionKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.DateAndTime;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class NetconfServerSession extends NetconfSession {
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class NetconfServerSession extends NetconfSession implements NetconfManagementSession {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfServerSession.class);
 
-    public NetconfServerSession(SessionListener sessionListener, Channel channel, long sessionId) {
-        super(sessionListener,channel,sessionId);
+    private final NetconfServerSessionNegotiator.AdditionalHeader header;
+
+    private Date loginTime;
+    private long inRpcSuccess, inRpcFail, outRpcError;
+
+    public NetconfServerSession(SessionListener sessionListener, Channel channel, long sessionId,
+            NetconfServerSessionNegotiator.AdditionalHeader header) {
+        super(sessionListener, channel, sessionId);
+        this.header = header;
         logger.debug("Session {} created", toString());
     }
+
+    @Override
+    protected void sessionUp() {
+        super.sessionUp();
+        Preconditions.checkState(loginTime == null, "Session is already up");
+        this.loginTime = new Date();
+    }
+
+    public void onIncommingRpcSuccess() {
+        inRpcSuccess++;
+    }
+
+    public void onIncommingRpcFail() {
+        inRpcFail++;
+    }
+
+    public void onOutgoingRpcError() {
+        outRpcError++;
+    }
+
+    public static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
+
+    @Override
+    public Session toManagementSession() {
+        SessionBuilder builder = new SessionBuilder();
+
+        builder.setSessionId(getSessionId());
+        builder.setSourceHost(new Host(new DomainName(header.getAddress())));
+
+        Preconditions.checkState(DateAndTime.PATTERN_CONSTANTS.size() == 1);
+        String formattedDateTime = formatDateTime(loginTime);
+        String pattern = DateAndTime.PATTERN_CONSTANTS.get(0);
+        Matcher matcher = Pattern.compile(pattern).matcher(formattedDateTime);
+        Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, pattern);
+        builder.setLoginTime(new DateAndTime(formattedDateTime));
+
+        builder.setInBadRpcs(new ZeroBasedCounter32(inRpcFail));
+        builder.setInRpcs(new ZeroBasedCounter32(inRpcSuccess));
+        builder.setOutRpcErrors(new ZeroBasedCounter32(outRpcError));
+
+        builder.setUsername(header.getUsername());
+        builder.setTransport(getTransportForString(header.getTransport()));
+
+        builder.setOutNotifications(new ZeroBasedCounter32(0L));
+
+        builder.setKey(new SessionKey(getSessionId()));
+        return builder.build();
+    }
+
+    private Class<? extends Transport> getTransportForString(String transport) {
+        switch(transport) {
+            case "ssh" : return NetconfSsh.class;
+            // TODO what about tcp
+            case "tcp" : return NetconfSsh.class;
+            default: throw new IllegalArgumentException("Unknown transport type " + transport);
+        }
+    }
+
+    private String formatDateTime(Date loginTime) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(ISO_DATE_FORMAT);
+        return dateFormat.format(loginTime);
+    }
+
 }
index 686adcad8550a3401809235cc0bda6e660782738..43e55d746a4ee59d1ec9bb35245f74e0edbca018 100644 (file)
@@ -8,13 +8,13 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import static com.google.common.base.Preconditions.checkState;
-
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
+import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
 import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
@@ -25,29 +25,32 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import static com.google.common.base.Preconditions.checkState;
 
 public class NetconfServerSessionListener implements
         SessionListener<NetconfMessage, NetconfServerSession, NetconfTerminationReason> {
 
     static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionListener.class);
     public static final String MESSAGE_ID = "message-id";
+    private final SessionMonitoringService monitoringService;
 
     private NetconfOperationRouterImpl operationRouter;
 
-    public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter) {
+    public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter,
+                                        SessionMonitoringService monitoringService) {
         this.operationRouter = operationRouter;
+        this.monitoringService = monitoringService;
     }
 
     @Override
     public void onSessionUp(NetconfServerSession netconfNetconfServerSession) {
-
+        monitoringService.onSessionUp(netconfNetconfServerSession);
     }
 
     @Override
     public void onSessionDown(NetconfServerSession netconfNetconfServerSession, Exception e) {
         logger.debug("Session {} down, reason: {}", netconfNetconfServerSession, e.getMessage());
+        monitoringService.onSessionDown(netconfNetconfServerSession);
 
         operationRouter.close();
     }
@@ -57,6 +60,7 @@ public class NetconfServerSessionListener implements
             NetconfTerminationReason netconfTerminationReason) {
         logger.debug("Session {} terminated, reason: {}", netconfNetconfServerSession,
                 netconfTerminationReason.getErrorMessage());
+        monitoringService.onSessionDown(netconfNetconfServerSession);
 
         operationRouter.close();
     }
@@ -70,7 +74,7 @@ public class NetconfServerSessionListener implements
             // schemas
             final NetconfMessage message = processDocument(netconfMessage,
                     session);
-            logger.debug("Respondign with message {}", XmlUtil.toString(message.getDocument()));
+            logger.debug("Responding with message {}", XmlUtil.toString(message.getDocument()));
             session.sendMessage(message);
 
             if (isCloseSession(netconfMessage)) {
@@ -78,10 +82,13 @@ public class NetconfServerSessionListener implements
             }
 
         } catch (final RuntimeException e) {
-            logger.error("Unexpected exception", e);
             // TODO: should send generic error or close session?
+            logger.error("Unexpected exception", e);
+            session.onIncommingRpcFail();
             throw new RuntimeException("Unable to process incoming message " + netconfMessage, e);
         } catch (NetconfDocumentedException e) {
+            session.onOutgoingRpcError();
+            session.onIncommingRpcFail();
             SendErrorExceptionUtil.sendErrorMessage(session, e, netconfMessage);
         }
     }
@@ -93,7 +100,7 @@ public class NetconfServerSessionListener implements
     }
 
     private NetconfMessage processDocument(final NetconfMessage netconfMessage,
-            NetconfSession session) throws NetconfDocumentedException {
+            NetconfServerSession session) throws NetconfDocumentedException {
 
         final Document incommingDocument = netconfMessage.getDocument();
         final Node rootNode = incommingDocument.getDocumentElement();
@@ -104,6 +111,9 @@ public class NetconfServerSessionListener implements
             final Document responseDocument = XmlUtil.newDocument();
             Document rpcReply = operationRouter.onNetconfMessage(
                     incommingDocument, session);
+
+            session.onIncommingRpcSuccess();
+
             responseDocument.appendChild(responseDocument.importNode(rpcReply.getDocumentElement(), true));
             return new NetconfMessage(responseDocument);
         } else {
index 70ddf299fd5dd0d7ff8c091598c0644a88278342..e25eaacdc06c9bbc0f9b600194bd9171787d1530 100644 (file)
@@ -12,6 +12,7 @@ import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 
 public class NetconfServerSessionListenerFactory implements SessionListenerFactory<NetconfServerSessionListener> {
@@ -22,12 +23,15 @@ public class NetconfServerSessionListenerFactory implements SessionListenerFacto
 
     private final SessionIdProvider idProvider;
 
+    private final SessionMonitoringService monitor;
+
     public NetconfServerSessionListenerFactory(NetconfOperationServiceFactoryListener factoriesListener,
-            DefaultCommitNotificationProducer commitNotifier,
-            SessionIdProvider idProvider) {
+                                               DefaultCommitNotificationProducer commitNotifier,
+                                               SessionIdProvider idProvider, SessionMonitoringService monitor) {
         this.factoriesListener = factoriesListener;
         this.commitNotifier = commitNotifier;
         this.idProvider = idProvider;
+        this.monitor = monitor;
     }
 
     @Override
@@ -41,6 +45,6 @@ public class NetconfServerSessionListenerFactory implements SessionListenerFacto
                 netconfOperationServiceSnapshot, capabilityProvider,
                 commitNotifier);
 
-        return new NetconfServerSessionListener(operationRouter);
+        return new NetconfServerSessionListener(operationRouter, monitor);
     }
 }
index e14ae3e4dca088cbd7d016ac119e6003bb8525a9..01ac018b3eadc3ee85d6ffd7a5e12fb8cbaf2daa 100644 (file)
@@ -8,26 +8,91 @@
 
 package org.opendaylight.controller.netconf.impl;
 
+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 org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
 import org.opendaylight.protocol.framework.SessionListener;
-import org.w3c.dom.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class NetconfServerSessionNegotiator extends
         AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession> {
 
+    static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
+
+    private static final AdditionalHeader DEFAULT_HEADER = new AdditionalHeader();
+
     protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
             Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener) {
         super(sessionPreferences, promise, channel, timer, sessionListener);
     }
 
     @Override
-    protected NetconfServerSession getSession(SessionListener sessionListener, Channel channel, Document doc) {
-        return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId());
+    protected NetconfServerSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) {
+        Optional<String> additionalHeader = message.getAdditionalHeader();
+
+        AdditionalHeader parsedHeader;
+        if (additionalHeader.isPresent()) {
+            parsedHeader = new AdditionalHeader(additionalHeader.get());
+        } else {
+            parsedHeader = DEFAULT_HEADER;
+        }
+        logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader);
+
+        return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader);
     }
 
+    static class AdditionalHeader {
+
+        private static final Pattern pattern = Pattern
+                .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
+        private final String username;
+        private final String address;
+        private final String transport;
+
+        public AdditionalHeader(String addHeaderAsString) {
+            addHeaderAsString = addHeaderAsString.trim();
+            Matcher matcher = pattern.matcher(addHeaderAsString);
+            Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
+                    addHeaderAsString, pattern);
+            this.username = matcher.group("username");
+            this.address = matcher.group("address");
+            this.transport = matcher.group("transport");
+        }
+
+        private AdditionalHeader() {
+            this.username = this.address = "unknown";
+            this.transport = "ssh";
+        }
+
+        String getUsername() {
+            return username;
+        }
+
+        String getAddress() {
+            return address;
+        }
+
+        String getTransport() {
+            return transport;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuffer sb = new StringBuffer("AdditionalHeader{");
+            sb.append("username='").append(username).append('\'');
+            sb.append(", address='").append(address).append('\'');
+            sb.append(", transport='").append(transport).append('\'');
+            sb.append('}');
+            return sb.toString();
+        }
+    }
 }
index 3623ef50325378b1c710d005248be520479c6763..cc503f60c3938947b8acb29882a9cd161bafda5c 100644 (file)
@@ -8,9 +8,9 @@
 
 package org.opendaylight.controller.netconf.impl.mapping.operations;
 
+import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
index 77042855e6525673a69fcce76344d5ea757b4061..ba9e4d0f8a14fe9cd44c906dc57a91011a89ca99 100644 (file)
@@ -11,9 +11,9 @@ package org.opendaylight.controller.netconf.impl.mapping.operations;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
index 8f08688f59dbcf456e7b4580bfbd8f1ea661235c..c18d0cc35f958bc543106810c91d3e11ced1d920 100644 (file)
@@ -7,9 +7,9 @@
  */\r
 package org.opendaylight.controller.netconf.impl.mapping.operations;\r
 \r
+import org.opendaylight.controller.netconf.api.NetconfSession;\r
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;\r
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;\r
-import org.opendaylight.controller.netconf.api.NetconfSession;\r
 import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;\r
 import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;\r
 import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;\r
index 98a72056827de18dbf034540ea56636a6ec3b922..2c6c89617ffbe19b1ff383604ba0e924fdb75ba6 100644 (file)
@@ -7,9 +7,9 @@
  */\r
 package org.opendaylight.controller.netconf.impl.mapping.operations;\r
 \r
+import org.opendaylight.controller.netconf.api.NetconfSession;\r
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;\r
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;\r
-import org.opendaylight.controller.netconf.api.NetconfSession;\r
 import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;\r
 import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;\r
 import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;\r
index b30c80b43d964426839306477a3c84a4d28084fd..abebacf974d0527b72d6479fb2e83796e18aedd4 100644 (file)
@@ -9,8 +9,7 @@ package org.opendaylight.controller.netconf.impl.osgi;
 
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
@@ -19,9 +18,15 @@ import org.opendaylight.controller.netconf.impl.SessionIdProvider;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
 public class NetconfImplActivator implements BundleActivator {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfImplActivator.class);
@@ -31,6 +36,7 @@ public class NetconfImplActivator implements BundleActivator {
     private NetconfServerDispatcher dispatch;
     private NioEventLoopGroup eventLoopGroup;
     private HashedWheelTimer timer;
+    private ServiceRegistration<NetconfMonitoringService> regMonitoring;
 
     @Override
     public void start(final BundleContext context) throws Exception {
@@ -38,8 +44,7 @@ public class NetconfImplActivator implements BundleActivator {
                 "TCP is not configured, netconf not available.", false);
 
         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
-        factoriesTracker = new NetconfOperationServiceFactoryTracker(context, factoriesListener);
-        factoriesTracker.open();
+        startOperationServiceFactoryTracker(context, factoriesListener);
 
         SessionIdProvider idProvider = new SessionIdProvider();
         timer = new HashedWheelTimer();
@@ -48,8 +53,10 @@ public class NetconfImplActivator implements BundleActivator {
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
+        NetconfMonitoringServiceImpl monitoringService = startMonitoringService(context, factoriesListener);
+
         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
-                factoriesListener, commitNot, idProvider);
+                factoriesListener, commitNot, idProvider, monitoringService);
 
         eventLoopGroup = new NioEventLoopGroup();
 
@@ -62,6 +69,19 @@ public class NetconfImplActivator implements BundleActivator {
 
     }
 
+    private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+        factoriesTracker = new NetconfOperationServiceFactoryTracker(context, factoriesListener);
+        factoriesTracker.open();
+    }
+
+    private NetconfMonitoringServiceImpl startMonitoringService(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+        NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener);
+        Dictionary<String, ?> dic = new Hashtable<>();
+        regMonitoring = context.registerService(NetconfMonitoringService.class, netconfMonitoringServiceImpl, dic);
+
+        return netconfMonitoringServiceImpl;
+    }
+
     @Override
     public void stop(final BundleContext context) throws Exception {
         logger.info("Shutting down netconf because YangStoreService service was removed");
@@ -69,5 +89,8 @@ public class NetconfImplActivator implements BundleActivator {
         commitNot.close();
         eventLoopGroup.shutdownGracefully();
         timer.stop();
+
+        regMonitoring.unregister();
+        factoriesTracker.close();
     }
 }
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java
new file mode 100644 (file)
index 0000000..1b35425
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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.impl.osgi;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.netty.util.internal.ConcurrentSet;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SessionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.SchemaBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.SchemaKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, SessionMonitoringService {
+
+    private static final Logger logger = LoggerFactory.getLogger(NetconfMonitoringServiceImpl.class);
+
+    private final Set<NetconfManagementSession> sessions = new ConcurrentSet<>();
+    private final NetconfOperationServiceFactoryListener factoriesListener;
+
+    public NetconfMonitoringServiceImpl(NetconfOperationServiceFactoryListener factoriesListener) {
+        this.factoriesListener = factoriesListener;
+    }
+
+    @Override
+    public void onSessionUp(NetconfManagementSession session) {
+        logger.debug("Session {} up", session);
+        Preconditions.checkState(sessions.contains(session) == false, "Session %s was already added", session);
+        sessions.add(session);
+    }
+
+    @Override
+    public void onSessionDown(NetconfManagementSession session) {
+        logger.debug("Session {} down", session);
+        Preconditions.checkState(sessions.contains(session) == true, "Session %s not present", session);
+        sessions.remove(session);
+    }
+
+    @Override
+    public Sessions getSessions() {
+        return new SessionsBuilder().setSession(transformSessions(sessions)).build();
+    }
+
+    @Override
+    public Schemas getSchemas() {
+        // FIXME, session ID
+        return transformSchemas(factoriesListener.getSnapshot(0));
+    }
+
+    private Schemas transformSchemas(NetconfOperationServiceSnapshot snapshot) {
+        Set<Capability> caps = Sets.newHashSet();
+
+        List<Schema> schemas = Lists.newArrayList();
+
+        for (NetconfOperationService netconfOperationService : snapshot.getServices()) {
+            // TODO check for duplicates ? move capability merging to snapshot
+            caps.addAll(netconfOperationService.getCapabilities());
+        }
+
+        for (Capability cap : caps) {
+            SchemaBuilder builder = new SchemaBuilder();
+
+            if(cap.getCapabilitySchema().isPresent() == false)
+                continue;
+
+            Preconditions.checkState(cap.getModuleNamespace().isPresent());
+            builder.setNamespace(new Uri(cap.getModuleNamespace().get()));
+
+            Preconditions.checkState(cap.getRevision().isPresent());
+            String version = cap.getRevision().get();
+            builder.setVersion(version);
+
+            Preconditions.checkState(cap.getModuleName().isPresent());
+            String identifier = cap.getModuleName().get();
+            builder.setIdentifier(identifier);
+
+            builder.setFormat(Yang.class);
+
+            builder.setLocation(transformLocations(cap.getLocation().or(Collections.<String> emptyList())));
+
+            builder.setKey(new SchemaKey(Yang.class, identifier, version));
+
+            schemas.add(builder.build());
+        }
+
+        return new SchemasBuilder().setSchema(schemas).build();
+    }
+
+    private List<Schema.Location> transformLocations(List<String> locations) {
+        List<Schema.Location> monitoringLocations = Lists.newArrayList();
+        monitoringLocations.add(new Schema.Location(Schema.Location.Enumeration.NETCONF));
+
+        for (String location : locations) {
+            // TODO how to create enumerration from string location ?
+            // monitoringLocations.add(new Schema.Location(Schema.Location.Enumeration.valueOf(location)));
+        }
+
+        return monitoringLocations;
+    }
+
+    private List<Session> transformSessions(Set<NetconfManagementSession> sessions) {
+        return Lists.newArrayList(Collections2.transform(sessions, new Function<NetconfManagementSession, Session>() {
+            @Nullable
+            @Override
+            public Session apply(@Nullable NetconfManagementSession input) {
+                return input.toManagementSession();
+            }
+        }));
+    }
+}
index 11b8dc623c8a07903df1d05da46407aef1770a47..ee474dbba01f4068de6190662c50d25f8339749d 100644 (file)
@@ -10,9 +10,9 @@ package org.opendaylight.controller.netconf.impl.osgi;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
@@ -53,8 +53,7 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
 
 
     public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
-            CapabilityProvider capabilityProvider,
-            DefaultCommitNotificationProducer commitNotifier) {
+            CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
 
         this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
 
@@ -65,12 +64,10 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
                 .getNetconfSessionIdForReporting()));
         defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
                 .getNetconfSessionIdForReporting()));
-        defaultNetconfOperations.add(new DefaultStartExi(
-                netconfOperationServiceSnapshot
-                        .getNetconfSessionIdForReporting()));
-        defaultNetconfOperations.add(new DefaultStopExi(
-                netconfOperationServiceSnapshot
-                        .getNetconfSessionIdForReporting()));
+        defaultNetconfOperations.add(new DefaultStartExi(netconfOperationServiceSnapshot
+                .getNetconfSessionIdForReporting()));
+        defaultNetconfOperations.add(new DefaultStopExi(netconfOperationServiceSnapshot
+                .getNetconfSessionIdForReporting()));
 
         allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
 
@@ -102,7 +99,8 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
         for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
             final Set<NetconfOperationFilter> filtersFromService = netconfOperationService.getFilters();
             for (NetconfOperationFilter filter : filtersFromService) {
-                Preconditions.checkState(result.contains(filter) == false, "Filter %s already present", filter);
+                Preconditions.checkState(result.contains(filter) == false,
+                        "Filter %s already present, all filters so far: %s", filter, result);
                 result.add(filter);
             }
         }
@@ -116,7 +114,7 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
     @Override
     public synchronized Document onNetconfMessage(Document message,
             NetconfSession session) throws NetconfDocumentedException {
-        NetconfOperationExecution netconfOperationExecution = null;
+        NetconfOperationExecution netconfOperationExecution;
 
         String messageAsString = XmlUtil.toString(message);
 
index 4d2bcb34fa687bcd0886c509d7678cae633be6dd..c1d9317c294ca96938dbd0ccec843eb7d5991d0f 100644 (file)
@@ -14,25 +14,25 @@ import org.osgi.util.tracker.ServiceTracker;
 
 class NetconfOperationServiceFactoryTracker extends
         ServiceTracker<NetconfOperationServiceFactory, NetconfOperationServiceFactory> {
-    private final NetconfOperationServiceFactoryListener operationRouter;
+    private final NetconfOperationServiceFactoryListener factoriesListener;
 
     NetconfOperationServiceFactoryTracker(BundleContext context,
-            final NetconfOperationServiceFactoryListener operationRouter) {
+            final NetconfOperationServiceFactoryListener factoriesListener) {
         super(context, NetconfOperationServiceFactory.class, null);
-        this.operationRouter = operationRouter;
+        this.factoriesListener = factoriesListener;
     }
 
     @Override
     public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
         NetconfOperationServiceFactory netconfOperationServiceFactory = super.addingService(reference);
-        operationRouter.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
+        factoriesListener.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
         return netconfOperationServiceFactory;
     }
 
     @Override
     public void removedService(ServiceReference<NetconfOperationServiceFactory> reference,
             NetconfOperationServiceFactory netconfOperationServiceFactory) {
-        operationRouter.onRemoveNetconfOperationServiceFactory(netconfOperationServiceFactory);
+        factoriesListener.onRemoveNetconfOperationServiceFactory(netconfOperationServiceFactory);
     }
 
 }
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/SessionMonitoringService.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/SessionMonitoringService.java
new file mode 100644 (file)
index 0000000..7a0b8b7
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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.impl.osgi;
+
+import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+
+public interface SessionMonitoringService {
+
+    void onSessionUp(NetconfManagementSession session);
+
+    void onSessionDown(NetconfManagementSession session);
+}
index b27cd2017292cd3995ff50db08ba952a44c4a03c..fca3e8bc1bd496f251687e7277beae6ec5020af9 100644 (file)
@@ -8,18 +8,21 @@
 
 package org.opendaylight.controller.netconf.impl.util;
 
-import java.util.Map;
-
-import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
+import com.google.common.collect.Maps;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.Maps;
+import java.util.Map;
 
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
+public final class
+        DeserializerExceptionHandler implements ChannelHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(DeserializerExceptionHandler.class);
 
-public final class DeserializerExceptionHandler implements ChannelHandler {
 
     @Override
     public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
@@ -33,9 +36,8 @@ public final class DeserializerExceptionHandler implements ChannelHandler {
 
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-        if (cause instanceof NetconfDeserializerException) {
-            handleDeserializerException(ctx, cause);
-        }
+        logger.warn("An exception occured during message handling", cause);
+        handleDeserializerException(ctx, cause);
     }
 
     private void handleDeserializerException(ChannelHandlerContext ctx, Throwable cause) {
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java
new file mode 100644 (file)
index 0000000..2f8fac2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.impl;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+public class AdditionalHeaderParserTest {
+
+    @Test
+    public void testParsing() throws Exception {
+        String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]";
+        NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+        Assert.assertEquals("netconf", header.getUsername());
+        Assert.assertEquals("10.12.0.102", header.getAddress());
+        Assert.assertEquals("ssh", header.getTransport());
+    }
+
+    @Test
+    public void testParsing2() throws Exception {
+        String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]";
+        NetconfServerSessionNegotiator.AdditionalHeader header = new NetconfServerSessionNegotiator.AdditionalHeader(s);
+        Assert.assertEquals("tomas", header.getUsername());
+        Assert.assertEquals("10.0.0.0", header.getAddress());
+        Assert.assertEquals("tcp", header.getTransport());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParsingNoUsername() throws Exception {
+        String s = "[10.12.0.102:48528;ssh;;;;;;]";
+        new NetconfServerSessionNegotiator.AdditionalHeader(s);
+    }
+}
index c0d2687a8a092b376f498e5cccadcaadfb816ab4..ce5233c494e6ddac78339709e9ae23dc5df05658 100644 (file)
@@ -14,18 +14,6 @@ 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;
@@ -43,6 +31,7 @@ import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.client.NetconfClient;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
+import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
 import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
@@ -54,9 +43,24 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
+
+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 java.util.concurrent.TimeUnit;
+
 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;
 
@@ -78,6 +82,8 @@ public class ConcurrentClientsTest {
     private DefaultCommitNotificationProducer commitNot;
     private NetconfServerDispatcher dispatch;
 
+    @Mock
+    private SessionMonitoringService monitoring;
 
     @Before
     public void setUp() throws Exception {
@@ -103,8 +109,11 @@ public class ConcurrentClientsTest {
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
+        doNothing().when(monitoring).onSessionUp(any(NetconfServerSession.class));
+        doNothing().when(monitoring).onSessionDown(any(NetconfServerSession.class));
+
         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
-                factoriesListener, commitNot, idProvider);
+                factoriesListener, commitNot, idProvider, monitoring);
         NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory, listenerFactory);
         dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
 
index eec96592d8e4e6e72e701a5596de52e17a1d7738..0140b65c146e4389ecc92e117d23685740ad3f4c 100644 (file)
@@ -12,14 +12,15 @@ import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
 
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+
 public class NetconfDispatcherImplTest {
 
     private EventLoopGroup nettyGroup;
@@ -46,7 +47,7 @@ public class NetconfDispatcherImplTest {
                 new HashedWheelTimer(), factoriesListener, idProvider);
 
         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
-                factoriesListener, commitNot, idProvider);
+                factoriesListener, commitNot, idProvider, null);
         NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory, listenerFactory);
 
 
index 410d9a96aa4a254b043901e74d3e19d8b049ead3..f2de91ef46d2be313b7626262076463fa8cc687d 100644 (file)
             <artifactId>netconf-impl</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-monitoring</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-mapping-api</artifactId>
index a2b87c113c2a2f9e3b5028edefadafb69863e880..91b543b4de90b2410501e91ddcf8d160d986149b 100644 (file)
@@ -77,7 +77,7 @@ public class NetconfITSecureTest extends AbstractConfigTest {
                 new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
 
         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
-                factoriesListener, commitNot, idProvider);
+                factoriesListener, commitNot, idProvider, NetconfITTest.getNetconfMonitoringListenerService());
 
         NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
                 serverNegotiatorFactory, listenerFactory);
index 9483785031b9c6fee67dbb8f5d4904767b5cd49a..c61dab7f643ebd119544cb12d76c0b420435d6af 100644 (file)
@@ -8,15 +8,18 @@
 
 package org.opendaylight.controller.netconf.it;
 
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.management.ManagementFactory;
@@ -24,20 +27,22 @@ import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import java.util.regex.Pattern;
+
 import javax.management.ObjectName;
 import javax.xml.parsers.ParserConfigurationException;
+
 import junit.framework.Assert;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
@@ -57,9 +62,11 @@ import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFa
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
 import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;
 import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
-import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.ExiParameters;
@@ -72,17 +79,18 @@ import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 public class NetconfITTest extends AbstractConfigTest {
 
-     private static final Logger logger =  LoggerFactory.getLogger(NetconfITTest.class);
-    //
+    // TODO refactor, pull common code up to AbstractNetconfITTest
+
+    private static final Logger logger =  LoggerFactory.getLogger(NetconfITTest.class);
 
     private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
     private static final InetSocketAddress sshAddress = new InetSocketAddress("127.0.0.1", 10830);
@@ -97,7 +105,6 @@ public class NetconfITTest extends AbstractConfigTest {
 
     private NetconfClientDispatcher clientDispatcher;
 
-
     @Before
     public void setUp() throws Exception {
         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(getModuleFactories().toArray(
@@ -125,13 +132,21 @@ public class NetconfITTest extends AbstractConfigTest {
                 new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
 
         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
-                factoriesListener, commitNot, idProvider);
+                factoriesListener, commitNot, idProvider, getNetconfMonitoringListenerService());
 
         NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
                 serverNegotiatorFactory, listenerFactory);
         return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
     }
 
+    static NetconfMonitoringServiceImpl getNetconfMonitoringListenerService() {
+        NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
+        NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+        doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
+        doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
+        return new NetconfMonitoringServiceImpl(factoriesListener);
+    }
+
     @After
     public void tearDown() throws Exception {
         commitNot.close();
@@ -204,14 +219,18 @@ public class NetconfITTest extends AbstractConfigTest {
         }
     }
 
+
+    //TODO: test persister actually
+    @Ignore
     @Test(timeout = 10000)
     public void testPersister() throws Exception {
-        Persister persister = mock(Persister.class);
-        doReturn("mockPersister").when(persister).toString();
-        doReturn(Optional.absent()).when(persister).loadLastConfig();
-        ConfigPersisterNotificationHandler h =
-                new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(), Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
-        h.init();
+//        Persister persister = mock(Persister.class);
+//        doReturn("mockPersister").when(persister).toString();
+//        doReturn(Collections.emptyList()).when(persister).loadLastConfigs();
+//        ConfigPersisterNotificationHandler h =
+//                new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(),
+//                        Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
+//        h.init();
     }
 
     @Ignore
@@ -369,23 +388,6 @@ public class NetconfITTest extends AbstractConfigTest {
         assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
     }
 
-    @Ignore
-    @Test
-    // TODO can only send NetconfMessage - it must be valid xml
-    public void testClientHelloWithAuth() throws Exception {
-        final String fileName = "netconfMessages/client_hello_with_auth.xml";
-        // final InputStream resourceAsStream =
-        // AbstractListenerTest.class.getResourceAsStream(fileName);
-        // assertNotNull(resourceAsStream);
-        try (NetconfClient netconfClient = new NetconfClient("test", tcpAddress, 5000, clientDispatcher)) {
-            // IOUtils.copy(resourceAsStream, netconfClient.getStream());
-            // netconfClient.getOutputStream().write(NetconfMessageFactory.endOfMessage);
-            // server should not write anything back
-            // assertEquals(null, netconfClient.readMessage());
-            assertGetConfigWorks(netconfClient);
-        }
-    }
-
     private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException {
         return assertGetConfigWorks(netconfClient, this.getConfig);
     }
diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java
new file mode 100644 (file)
index 0000000..244e4ba
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * 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 com.google.common.base.Charsets;
+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 junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
+import org.mockito.Mock;
+import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yang.store.api.YangStoreException;
+import org.opendaylight.controller.config.yang.store.impl.HardcodedYangStoreService;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+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;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
+import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class NetconfMonitoringITTest extends AbstractConfigTest {
+
+    private static final Logger logger =  LoggerFactory.getLogger(NetconfITTest.class);
+
+    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
+
+    @Mock
+    private DefaultCommitNotificationProducer commitNot;
+    private NetconfServerDispatcher dispatch;
+    private EventLoopGroup nettyThreadgroup;
+
+    private NetconfClientDispatcher clientDispatcher;
+
+    private NetconfMonitoringServiceImpl monitoringService;
+
+    @Before
+    public void setUp() throws Exception {
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(NetconfITTest.getModuleFactoriesS().toArray(
+                new ModuleFactory[0])));
+
+        monitoringService = new NetconfMonitoringServiceImpl(getFactoriesListener());
+
+        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
+        factoriesListener
+                .onAddNetconfOperationServiceFactory(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
+                        new NetconfMonitoringOperationService(monitoringService)));
+
+        nettyThreadgroup = new NioEventLoopGroup();
+
+        dispatch = createDispatcher(factoriesListener);
+        ChannelFuture s = dispatch.createServer(tcpAddress);
+        s.await();
+
+        clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup);
+    }
+
+    private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
+        final Collection<InputStream> yangDependencies = NetconfITTest.getBasicYangs();
+        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, commitNot, idProvider, getNetconfMonitoringListenerService(logger, monitoringService));
+
+        NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
+                serverNegotiatorFactory, listenerFactory);
+        return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
+    }
+
+    static SessionMonitoringService getNetconfMonitoringListenerService(final Logger logger, final NetconfMonitoringServiceImpl monitor) {
+        return new SessionMonitoringService() {
+            @Override
+            public void onSessionUp(NetconfManagementSession session) {
+                logger.debug("Management session up {}", session);
+                monitor.onSessionUp(session);
+            }
+
+            @Override
+            public void onSessionDown(NetconfManagementSession session) {
+                logger.debug("Management session down {}", session);
+                monitor.onSessionDown(session);
+            }
+        };
+    }
+
+
+    @Test
+    public void testGetResponseFromMonitoring() throws Exception {
+        try (NetconfClient netconfClient = new NetconfClient("client-monitoring", tcpAddress, 4000, clientDispatcher)) {
+        try (NetconfClient netconfClient2 = new NetconfClient("client-monitoring2", tcpAddress, 4000, clientDispatcher)) {
+            NetconfMessage response = netconfClient.sendMessage(loadGetMessage());
+            assertSessionElementsInResponse(response.getDocument(), 2);
+        }
+            NetconfMessage response = netconfClient.sendMessage(loadGetMessage());
+            assertSessionElementsInResponse(response.getDocument(), 1);
+        }
+    }
+
+
+    @Test(timeout = 5 * 10000)
+    public void testClientHelloWithAuth() throws Exception {
+        String fileName = "netconfMessages/client_hello_with_auth.xml";
+        String hello = XmlFileLoader.fileToString(fileName);
+
+        fileName = "netconfMessages/get.xml";
+        String get = XmlFileLoader.fileToString(fileName);
+
+        Socket sock = new Socket(tcpAddress.getHostName(), tcpAddress.getPort());
+        sock.getOutputStream().write(hello.getBytes(Charsets.UTF_8));
+        String separator = "]]>]]>";
+
+        sock.getOutputStream().write(separator.getBytes(Charsets.UTF_8));
+        sock.getOutputStream().write(get.getBytes(Charsets.UTF_8));
+        sock.getOutputStream().write(separator.getBytes(Charsets.UTF_8));
+
+        StringBuilder responseBuilder = new StringBuilder();
+
+        try (InputStream inputStream = sock.getInputStream();
+             InputStreamReader reader = new InputStreamReader(inputStream);
+             BufferedReader buff = new BufferedReader(reader)) {
+            String line;
+            while ((line = buff.readLine()) != null) {
+
+                responseBuilder.append(line);
+                responseBuilder.append(System.lineSeparator());
+                System.out.println(responseBuilder.toString());
+
+                if(line.contains("</rpc-reply>"))
+                    break;
+            }
+        }
+
+        org.junit.Assert.assertThat(responseBuilder.toString(), JUnitMatchers.containsString("<capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>"));
+        org.junit.Assert.assertThat(responseBuilder.toString(), JUnitMatchers.containsString("<username>tomas</username>"));
+    }
+
+    private void assertSessionElementsInResponse(Document document, int i) {
+        int elementSize = document.getElementsByTagName("session-id").getLength();
+        Assert.assertEquals(i, elementSize);
+    }
+
+    private NetconfMessage loadGetMessage() throws Exception {
+        return XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/get.xml");
+    }
+
+    public NetconfOperationServiceFactoryListener getFactoriesListener() {
+        NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
+        NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+        NetconfOperationService service = mock(NetconfOperationService.class);
+        Set<Capability> caps = Sets.newHashSet();
+        caps.add(new Capability() {
+            @Override
+            public String getCapabilityUri() {
+                return "namespaceModuleRevision";
+            }
+
+            @Override
+            public Optional<String> getModuleNamespace() {
+                return Optional.of("namespace");
+            }
+
+            @Override
+            public Optional<String> getModuleName() {
+                return Optional.of("name");
+            }
+
+            @Override
+            public Optional<String> getRevision() {
+                return Optional.of("revision");
+            }
+
+            @Override
+            public Optional<String> getCapabilitySchema() {
+                return Optional.of("content");
+            }
+
+            @Override
+            public Optional<List<String>> getLocation() {
+                return Optional.absent();
+            }
+        });
+
+        doReturn(caps).when(service).getCapabilities();
+        Set<NetconfOperationService> services = Sets.newHashSet(service);
+        doReturn(services).when(snap).getServices();
+        doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
+
+        return factoriesListener;
+    }
+
+
+}
index 6351c617cf505aad255eb90ee9921d46c53643bf..3dc7155317dbf769c3acdc0edc56a873e6e8dfaa 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.controller.netconf.mapping.api;
 
 import com.google.common.base.Optional;
 
+import java.util.List;
+
 /**
  * Contains capability URI announced by server hello message and optionally its
  * corresponding yang schema that can be retrieved by get-schema rpc.
@@ -18,9 +20,13 @@ public interface Capability {
 
     public String getCapabilityUri();
 
+    public Optional<String> getModuleNamespace();
+
     public Optional<String> getModuleName();
 
     public Optional<String> getRevision();
 
     public Optional<String> getCapabilitySchema();
+
+    public Optional<List<String>> getLocation();
 }
diff --git a/opendaylight/netconf/netconf-monitoring/pom.xml b/opendaylight/netconf/netconf-monitoring/pom.xml
new file mode 100644 (file)
index 0000000..31e4271
--- /dev/null
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>netconf-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>netconf-monitoring</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+
+    <dependencies>
+        <!-- compile dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-mapping-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <version>${bgpcep.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator</Bundle-Activator>
+                        <Import-Package>
+                            com.google.common.base,
+                            com.google.common.collect,
+                            com.google.common.io,
+                            org.opendaylight.controller.netconf.api,
+                            org.opendaylight.controller.netconf.mapping.api,
+                            org.opendaylight.controller.netconf.util.mapping,
+                            org.osgi.framework,
+                            org.slf4j,
+                            org.w3c.dom,
+                            javax.xml.bind,
+                            javax.xml.bind.annotation,
+                            javax.xml.transform,
+                            javax.xml.transform.dom,
+                            org.opendaylight.controller.netconf.util.xml,
+                            io.netty.util.internal,
+                            javax.annotation,
+                            org.opendaylight.controller.netconf.api.monitoring,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
+                            org.osgi.util.tracker,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
+                            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/Get.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/Get.java
new file mode 100644 (file)
index 0000000..0b923f6
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.monitoring;
+
+import com.google.common.collect.Maps;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilterChain;
+import org.opendaylight.controller.netconf.monitoring.xml.JaxBSerializer;
+import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
+import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.Map;
+
+public class Get implements NetconfOperationFilter {
+
+    private static final Logger logger = LoggerFactory.getLogger(Get.class);
+    private final NetconfMonitoringService netconfMonitor;
+
+    public Get(NetconfMonitoringService netconfMonitor) {
+        this.netconfMonitor = netconfMonitor;
+    }
+
+    @Override
+    public Document doFilter(Document message, NetconfOperationRouter operationRouter,
+            NetconfOperationFilterChain filterChain) throws NetconfDocumentedException {
+        AbstractNetconfOperation.OperationNameAndNamespace operationNameAndNamespace = new AbstractNetconfOperation.OperationNameAndNamespace(
+                message);
+        if (canHandle(operationNameAndNamespace)) {
+            return handle(message, operationRouter, filterChain);
+        }
+        return filterChain.execute(message, operationRouter);
+    }
+
+    private Document handle(Document message, NetconfOperationRouter operationRouter,
+            NetconfOperationFilterChain filterChain) throws NetconfDocumentedException {
+        try {
+            Document innerResult = filterChain.execute(message, operationRouter);
+
+            NetconfState netconfMonitoring = new NetconfState(netconfMonitor);
+            Element monitoringXmlElement = new JaxBSerializer().toXml(netconfMonitoring);
+
+            monitoringXmlElement = (Element) innerResult.importNode(monitoringXmlElement, true);
+            Element monitoringXmlElementPlaceholder = getPlaceholder(innerResult);
+            monitoringXmlElementPlaceholder.appendChild(monitoringXmlElement);
+
+            return innerResult;
+        } catch (RuntimeException e) {
+            String errorMessage = "Get operation for netconf-state subtree failed";
+            logger.warn(errorMessage, e);
+            Map<String, String> info = Maps.newHashMap();
+            info.put(NetconfDocumentedException.ErrorSeverity.error.toString(), e.getMessage());
+            throw new NetconfDocumentedException(errorMessage, NetconfDocumentedException.ErrorType.application,
+                    NetconfDocumentedException.ErrorTag.operation_failed,
+                    NetconfDocumentedException.ErrorSeverity.error, info);
+        }
+    }
+
+    private Element getPlaceholder(Document innerResult) {
+        try {
+            XmlElement rootElement = XmlElement.fromDomElementWithExpected(innerResult.getDocumentElement(),
+                    XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
+            return rootElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY).getDomElement();
+        } catch (RuntimeException e) {
+            throw new IllegalArgumentException(String.format(
+                    "Input xml in wrong format, Expecting root element %s with child element %s, but was %s",
+                    XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.DATA_KEY,
+                    XmlUtil.toString(innerResult.getDocumentElement())), e);
+        }
+    }
+
+    private boolean canHandle(AbstractNetconfOperation.OperationNameAndNamespace operationNameAndNamespace) {
+        if (operationNameAndNamespace.getOperationName().equals(XmlNetconfConstants.GET) == false)
+            return false;
+        return operationNameAndNamespace.getNamespace().equals(
+                XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+    }
+
+    @Override
+    public int getSortingOrder() {
+        // FIXME filters for different operations cannot have same order
+        return 1;
+    }
+
+    @Override
+    public int compareTo(NetconfOperationFilter o) {
+        return Integer.compare(getSortingOrder(), o.getSortingOrder());
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java
new file mode 100644 (file)
index 0000000..3a9d3ba
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * 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.monitoring;
+
+public class MonitoringConstants {
+
+    public static final String NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
+    public static final String MODULE_NAME = "ietf-netconf-monitoring";
+    public static final String MODULE_REVISION = "2010-10-04";
+
+    public static final String URI = String.format("%s?module=%s&revision=%s", NAMESPACE, MODULE_NAME, MODULE_REVISION);
+
+    public static final String NETCONF_MONITORING_XML_ROOT_ELEMENT = "netconf-state";
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java
new file mode 100644 (file)
index 0000000..1143231
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+* 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.monitoring.osgi;
+
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfMonitoringActivator implements BundleActivator {
+
+    private static final Logger logger = LoggerFactory.getLogger(NetconfMonitoringActivator.class);
+
+    private NetconfMonitoringServiceTracker monitor;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        monitor = new NetconfMonitoringServiceTracker(context);
+        monitor.open();
+
+    }
+
+    @Override
+    public void stop(final BundleContext context) throws Exception {
+        if(monitor!=null) {
+            try {
+                monitor.close();
+            } catch (Exception e) {
+                logger.warn("Ignoring exception while closing {}", monitor, e);
+            }
+        }
+    }
+
+    public static class NetconfMonitoringOperationServiceFactory implements NetconfOperationServiceFactory {
+        private final NetconfMonitoringOperationService operationService;
+
+        public NetconfMonitoringOperationServiceFactory(NetconfMonitoringOperationService operationService) {
+            this.operationService = operationService;
+        }
+
+        @Override
+        public NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting) {
+            return operationService;
+        }
+    }
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationService.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationService.java
new file mode 100644 (file)
index 0000000..fe01847
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+* 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.monitoring.osgi;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.monitoring.Get;
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class NetconfMonitoringOperationService implements NetconfOperationService {
+
+    public static final HashSet<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
+
+        @Override
+        public String getCapabilityUri() {
+            return MonitoringConstants.URI;
+        }
+
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.of(MonitoringConstants.NAMESPACE);
+        }
+
+        @Override
+        public Optional<String> getModuleName() {
+            return Optional.of(MonitoringConstants.MODULE_NAME);
+        }
+
+        @Override
+        public Optional<String> getRevision() {
+            return Optional.of(MonitoringConstants.MODULE_REVISION);
+        }
+
+        @Override
+        public Optional<String> getCapabilitySchema() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<List<String>> getLocation() {
+            return Optional.absent();
+        }
+    });
+
+    private final NetconfMonitoringService monitor;
+
+    public NetconfMonitoringOperationService(NetconfMonitoringService monitor) {
+        this.monitor = monitor;
+    }
+
+    private static String readSchema() {
+        String schemaLocation = "/META-INF/yang/ietf-netconf-monitoring.yang";
+        URL resource = Schemas.class.getClassLoader().getResource(schemaLocation);
+        Preconditions.checkNotNull(resource, "Unable to read schema content from %s", schemaLocation);
+        File file = new File(resource.getFile());
+        try {
+            return Files.toString(file, Charsets.UTF_8);
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to load schema from " + schemaLocation, e);
+        }
+    }
+
+    @Override
+    public Set<Capability> getCapabilities() {
+        return CAPABILITIES;
+    }
+
+    @Override
+    public Set<NetconfOperation> getNetconfOperations() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<NetconfOperationFilter> getFilters() {
+        return Sets.<NetconfOperationFilter>newHashSet(new Get(monitor));
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTracker.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTracker.java
new file mode 100644 (file)
index 0000000..920236b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.monitoring.osgi;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+public class NetconfMonitoringServiceTracker extends ServiceTracker<NetconfMonitoringService, NetconfMonitoringService> {
+
+    private static final Logger logger = LoggerFactory.getLogger(NetconfMonitoringServiceTracker.class);
+
+    private ServiceRegistration<NetconfOperationServiceFactory> reg;
+
+    NetconfMonitoringServiceTracker(BundleContext context) {
+        super(context, NetconfMonitoringService.class, null);
+    }
+
+    @Override
+    public NetconfMonitoringService addingService(ServiceReference<NetconfMonitoringService> reference) {
+        Preconditions.checkState(reg == null, "Monitoring service was already added");
+
+        NetconfMonitoringService netconfMonitoringService = super.addingService(reference);
+
+        final NetconfMonitoringOperationService operationService = new NetconfMonitoringOperationService(
+                netconfMonitoringService);
+        NetconfOperationServiceFactory factory = new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
+                operationService);
+
+        Dictionary<String, ?> props = new Hashtable<>();
+        reg = context.registerService(NetconfOperationServiceFactory.class, factory, props);
+
+        return netconfMonitoringService;
+    }
+
+    @Override
+    public void removedService(ServiceReference<NetconfMonitoringService> reference,
+            NetconfMonitoringService netconfMonitoringService) {
+        if(reg!=null) {
+            try {
+                reg.unregister();
+            } catch (Exception e) {
+                logger.warn("Ignoring exception while unregistering {}", reg, e);
+            }
+        }
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializer.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializer.java
new file mode 100644 (file)
index 0000000..4b07ab0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.monitoring.xml;
+
+import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.transform.dom.DOMResult;
+
+public class JaxBSerializer {
+
+    public Element toXml(NetconfState monitoringModel) {
+        DOMResult res = null;
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(NetconfState.class);
+            Marshaller marshaller = jaxbContext.createMarshaller();
+
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+
+            res = new DOMResult();
+            marshaller.marshal(monitoringModel, res);
+        } catch (JAXBException e) {
+           throw new RuntimeException("Unable to serialize netconf state " + monitoringModel, e);
+        }
+        return ((Document)res.getNode()).getDocumentElement();
+    }
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSchema.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSchema.java
new file mode 100644 (file)
index 0000000..078509d
--- /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.monitoring.xml.model;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+
+import javax.annotation.Nullable;
+import javax.xml.bind.annotation.XmlElement;
+import java.util.Collection;
+
+final class MonitoringSchema {
+
+    private final Schema schema;
+
+    public MonitoringSchema(Schema schema) {
+        this.schema = schema;
+    }
+
+    @XmlElement(name = "identifier")
+    public String getIdentifier() {
+        return schema.getIdentifier();
+    }
+
+    @XmlElement(name = "namespace")
+    public String getNamespace() {
+        return schema.getNamespace().getValue().toString();
+    }
+
+    @XmlElement(name = "location")
+    public Collection<String> getLocation() {
+        return Collections2.transform(schema.getLocation(), new Function<Schema.Location, String>() {
+            @Nullable
+            @Override
+            public String apply(@Nullable Schema.Location input) {
+                return input.getEnumeration().toString();
+            }
+        });
+    }
+
+    @XmlElement(name = "version")
+    public String getVersion() {
+        return schema.getVersion();
+    }
+
+    @XmlElement(name = "format")
+    public String getFormat() {
+        Preconditions.checkState(schema.getFormat() == Yang.class, "Only yang format permitted, but was %s", schema.getFormat());
+        return "yang";
+    }
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java
new file mode 100644 (file)
index 0000000..25fb5d4
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.monitoring.xml.model;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+final class MonitoringSession {
+
+    @XmlTransient
+    private Session managementSession;
+
+    public MonitoringSession(Session managementSession) {
+        this.managementSession = managementSession;
+    }
+
+    public MonitoringSession() {
+    }
+
+    public void setManagementSession(Session managementSession) {
+        this.managementSession = managementSession;
+    }
+
+    @XmlElement(name = "session-id")
+    public long getId() {
+        return managementSession.getSessionId();
+    }
+
+    @XmlElement(name = "source-host")
+    public String getSourceHost() {
+        return managementSession.getSourceHost().getDomainName().getValue();
+    }
+
+    @XmlElement(name = "login-time")
+    public String getLoginTime() {
+        return managementSession.getLoginTime().getValue();
+    }
+
+    @XmlElement(name = "in-bad-rpcs")
+    public Long getInBadRpcs() {
+        return managementSession.getInBadRpcs().getValue();
+    }
+
+    @XmlElement(name = "in-rpcs")
+    public Long getInRpcs() {
+        return managementSession.getInRpcs().getValue();
+    }
+
+    @XmlElement(name = "out-notifications")
+    public Long getOutNotifications() {
+        return managementSession.getOutNotifications().getValue();
+    }
+
+    @XmlElement(name = "out-rpc-errors")
+    public Long getOutRpcErrors() {
+        return managementSession.getOutRpcErrors().getValue();
+    }
+
+    @XmlElement(name = "transport")
+    public String getTransport() {
+        Preconditions.checkState(managementSession.getTransport() == NetconfSsh.class);
+        return "netconf-ssh";
+    }
+
+    @XmlElement(name = "username")
+    public String getUsername() {
+        return managementSession.getUsername();
+    }
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/NetconfState.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/NetconfState.java
new file mode 100644 (file)
index 0000000..98bda58
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.monitoring.xml.model;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+
+import javax.annotation.Nullable;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Collection;
+
+@XmlRootElement(name = MonitoringConstants.NETCONF_MONITORING_XML_ROOT_ELEMENT)
+public final class NetconfState {
+
+    private Schemas schemas;
+    private Sessions sessions;
+
+    public NetconfState(NetconfMonitoringService monitoringService) {
+        this.sessions = monitoringService.getSessions();
+        this.schemas = monitoringService.getSchemas();
+    }
+
+    public NetconfState() {
+    }
+
+
+
+    @XmlElementWrapper(name="schemas")
+    @XmlElement(name="schema")
+    public Collection<MonitoringSchema> getSchemas() {
+        return Collections2.transform(schemas.getSchema(), new Function<Schema, MonitoringSchema>() {
+            @Nullable
+            @Override
+            public MonitoringSchema apply(@Nullable Schema input) {
+                return new MonitoringSchema(input);
+            }
+        });
+    }
+
+    @XmlElementWrapper(name="sessions")
+    @XmlElement(name="session")
+    public Collection<MonitoringSession> getSessions() {
+        return Collections2.transform(sessions.getSession(), new Function<Session, MonitoringSession>() {
+            @Nullable
+            @Override
+            public MonitoringSession apply(@Nullable Session input) {
+                return new MonitoringSession(input);
+            }
+        });
+    }
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java
new file mode 100644 (file)
index 0000000..8771421
--- /dev/null
@@ -0,0 +1,13 @@
+@XmlSchema(
+        elementFormDefault = XmlNsForm.QUALIFIED,
+//        xmlns = {
+//                @XmlNs(namespaceURI = MonitoringConstants.NAMESPACE, prefix = "")
+//        }
+        namespace = MonitoringConstants.NAMESPACE
+)
+package org.opendaylight.controller.netconf.monitoring.xml.model;
+
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java
new file mode 100644 (file)
index 0000000..cb6e59f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+* 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.monitoring.xml;
+
+import com.google.common.collect.Lists;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SessionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.DateAndTime;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32;
+import org.w3c.dom.Element;
+
+import java.util.Date;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class JaxBSerializerTest {
+
+    @Test
+    public void testName() throws Exception {
+
+        NetconfMonitoringService service = new NetconfMonitoringService() {
+
+            @Override
+            public Sessions getSessions() {
+                return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession())).build();
+            }
+
+            @Override
+            public Schemas getSchemas() {
+                return new SchemasBuilder().setSchema(Lists.<Schema>newArrayList()).build();
+            }
+        };
+        NetconfState model = new NetconfState(service);
+        Element xml = new JaxBSerializer().toXml(model);
+        System.out.println(XmlUtil.toString(xml));
+    }
+
+    private Session getMockSession() {
+        Session mocked = mock(Session.class);
+        doReturn(1L).when(mocked).getSessionId();
+        doReturn(new DateAndTime(new Date().toString())).when(mocked).getLoginTime();
+        doReturn(new Host(new DomainName("address/port"))).when(mocked).getSourceHost();
+        doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInBadRpcs();
+        doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInRpcs();
+        doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutNotifications();
+        doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors();
+        doReturn(NetconfSsh.class).when(mocked).getTransport();
+        doReturn("username").when(mocked).getUsername();
+        return mocked;
+    }
+}
index 3ed75a1b1684af1085347b9e822479720a5da83e..95d2feb65c482ea564bce7794d61d6360e35f379 100644 (file)
@@ -20,8 +20,8 @@ import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GenericFutureListener;
 import io.netty.util.concurrent.Promise;
 
-import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
@@ -130,16 +130,17 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
                 channel.pipeline().addAfter("aggregator", "chunkDecoder", new NetconfMessageChunkDecoder());
             }
             changeState(State.ESTABLISHED);
-            S session = getSession(sessionListener, channel, doc);
+            S session = getSession(sessionListener, channel, netconfMessage);
             negotiationSuccessful(session);
         } else {
             final IllegalStateException cause = new IllegalStateException(
                     "Received message was not hello as expected, but was " + XmlUtil.toString(doc));
+            logger.warn("Negotiation of netconf session failed", cause);
             negotiationFailed(cause);
         }
     }
 
-    protected abstract S getSession(SessionListener sessionListener, Channel channel, Document doc);
+    protected abstract S getSession(SessionListener sessionListener, Channel channel, NetconfMessage message);
 
     private boolean isHelloMessage(Document doc) {
         try {
index 0b6914ec2ae44f12f5c4ade5a9c9574c7b2a7de6..891d40cf74fa520be681aa73109765424f5ab8e8 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.util.messages;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
 import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -27,6 +28,7 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * NetconfMessageFactory for (de)serializing DOM documents.
@@ -47,26 +49,65 @@ public final class NetconfMessageFactory implements ProtocolMessageFactory<Netco
 
     @Override
     public NetconfMessage parse(byte[] bytes) throws DeserializerException, DocumentedException {
-        String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
-        logger.debug("Parsing message \n{}", s);
-        if (bytes[0] == '[') {
-            // yuma sends auth information in the first line. Ignore until ]\n
-            // is found.
-            int endOfAuthHeader = ByteArray.findByteSequence(bytes, new byte[] { ']', '\n' });
+        logMessage(bytes);
+
+        String additionalHeader = null;
+
+        if (startsWithAdditionalHeader(bytes)) {
+            // Auth information containing username, ip address... extracted for monitoring
+            int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
             if (endOfAuthHeader > -1) {
+                byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
+                additionalHeader = additionalHeaderToString(additionalHeaderBytes);
                 bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
             }
         }
-        NetconfMessage message = null;
+        NetconfMessage message;
         try {
             Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
-            message = new NetconfMessage(doc);
+            message = new NetconfMessage(doc, additionalHeader);
         } catch (final SAXException | IOException | IllegalStateException e) {
             throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e);
         }
         return message;
     }
 
+    private int getAdditionalHeaderEndIndex(byte[] bytes) {
+        for (String possibleEnd : Lists.newArrayList("]\n", "]\r\n")) {
+            int idx = ByteArray.findByteSequence(bytes, possibleEnd.getBytes(Charsets.UTF_8));
+
+            if (idx != -1) {
+                return idx;
+            }
+        }
+
+        return -1;
+    }
+
+    private boolean startsWithAdditionalHeader(byte[] bytes) {
+        List<String> possibleStarts = Lists.newArrayList("[", "\r\n[", "\n[");
+        for (String possibleStart : possibleStarts) {
+            int i = 0;
+            for (byte b : possibleStart.getBytes(Charsets.UTF_8)) {
+                if(bytes[i]!=b)
+                    break;
+
+                return true;
+            }
+        }
+
+        return false;
+    };
+
+    private void logMessage(byte[] bytes) {
+        String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
+        logger.debug("Parsing message \n{}", s);
+    }
+
+    private String additionalHeaderToString(byte[] bytes) {
+        return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
+    }
+
     @Override
     public byte[] put(NetconfMessage netconfMessage) {
         if (clientId.isPresent()) {
index cb3606cb4cb06fd7f6535728509b84988c6dd784..a43216917befd447ec4a6aedb1b82b31934e1633 100644 (file)
@@ -10,9 +10,9 @@ package org.opendaylight.controller.netconf.util.messages;
 
 import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
+import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
index 7fb293f054e40aff5e3d840488a4b3b9047e8110..c410cf30b0abd00290bbc178c5ea3c9cbc7c0a21 100644 (file)
@@ -43,4 +43,5 @@ public class XmlNetconfConstants {
     public static final String URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
     // TODO where to store namespace of config ?
     public static final String URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG = "urn:opendaylight:params:xml:ns:yang:controller:config";
+    public static final String GET = "get";
 }
diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java
new file mode 100644 (file)
index 0000000..f8c9083
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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.util.messages;
+
+import com.google.common.io.Files;
+import org.junit.Test;
+
+import java.io.File;
+
+public class NetconfMessageFactoryTest {
+
+
+    @Test
+    public void testAuth() throws Exception {
+        NetconfMessageFactory parser = new NetconfMessageFactory();
+        File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile());
+        parser.parse(Files.toByteArray(authHelloFile));
+
+    }
+}
index 174640c4f9164d92fc8ff6ef68f3c805655d3d14..c0aaf8f23dc83b482cb6095159231dcb84b32a91 100644 (file)
@@ -1,8 +1,6 @@
 [tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]
-        <?xml version="1.0" encoding="UTF-8"?>
-<hello
-        xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <capabilities>
         <capability>urn:ietf:params:netconf:base:1.0</capability>
     </capabilities>
-</hello>
+</hello>
\ No newline at end of file
index caa0094c4b2b31a1259df17b536ebdb84d89a8b6..dc522d2e64a5601f019e0ce9be476bb2d7e7df71 100644 (file)
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                         <name>ref_dep</name>
                     </testing-dep>
+
+                    <testing-deps>
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+                        <name>ref_dep</name>
+                    </testing-deps>
+                    <testing-deps>
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+                        <name>ref_dep_2</name>
+                    </testing-deps>
                 </module>
 
                 <module>
 
                     <testing-dep>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
-                        <name>ref_dep</name>
+                        <name>ref_dep_2</name>
                     </testing-dep>
                 </module>
             </modules>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index c825536b7b320e511d0ad3e96335cf692dd6258b..388aa4f2ab6b528d8e701be6e9689d5513395ad2 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 82c218dd73620a3c4d5f45b6330a8ce74daef8f0..4d94d9e94962a529fc666eafc5c3ffac077cef5e 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 7c19b9f7b3b9005fda4f339704ad6f887dcc82a8..c399c196d37174a9df5bba448f44d4b7fbdd441d 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 84ae57555952c30f8bfa8500841405958743d69d..47b82c6114f6048fa4a42fd4a8482ac8665162b0 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 2d9e9edb2c4a00d92fe77b5a444052f112427c48..0e70e13a34417b885193310f12b803d6c007e2d2 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 9407dd0c7539d7269e19ed2d96ded86b1d9d4d41..bc05d6393181bc379659b33580bbdda0c22f8e7b 100644 (file)
@@ -27,7 +27,7 @@
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 233ad23286fa12d4d003400c945d2001215ac7fe..f20d9ff9fa16ea1cb93725d3e81463fb4b03a2bb 100644 (file)
@@ -28,7 +28,7 @@
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 4593887f49ccae613b92666cbef245d54e2249c1..ff0bd9feb5dc31ab7e19ce14132a9af6d1df3611 100644 (file)
@@ -29,7 +29,7 @@
 
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 81c4137d4e88c8a0b8414d7d2396a746d02c9c48..906367b7a6257277ae4d391dd7fe3b8301fd343e 100644 (file)
@@ -29,7 +29,7 @@
                     <instance>
                         <name>ref_dep</name>
                         <unknownAttribute>error</unknownAttribute>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index 528d5b06fcc63f0e7f3a50427687a0056881633b..b05046db4b15b18294c3b8f314d39fbf9e2d34d9 100644 (file)
@@ -26,7 +26,7 @@
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                 </service>
index a1e304b374686390c17eb5a4360aad631f41a166..d03bb084b824370f00bd84986dcd5ae6b6746dff 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index 812882a2a97da77bed74c9ec8e4421874ee6969d..3722973912192f79c7b70700e4172cdcb888d2cb 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                     <instance>
                         <name>ref_dep</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep']
+                        <provider>/modules/module[type='impl-dep'][name='dep']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_dep_2</name>
-                        <provider>/config/modules/module[name='impl-dep']/instance[name='dep2']
+                        <provider>/modules/module[type='impl-dep'][name='dep2']
                         </provider>
                     </instance>
                     <instance>
                         <name>ref_test1</name>
-                        <provider>/config/modules/module[name='impl-netconf']/instance[name='test1']
+                        <provider>
+                            /modules/module[type='impl-netconf'][name='test1']
                         </provider>
                     </instance>
                 </service>
index ad8356431ecc4777bfee0bd1b1e7717c1a7af039..52b7370e35fa51d97806a66062a280ca595ff80a 100644 (file)
@@ -29,6 +29,8 @@
         <module>netconf-ssh</module>
         <module>../../third-party/ganymed</module>
         <module>../../third-party/com.siemens.ct.exi</module>
+        <module>netconf-monitoring</module>
+        <module>ietf-netconf-monitoring</module>
     </modules>
 
     <profiles>
                 <artifactId>netconf-impl</artifactId>
                 <version>${netconf.version}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>netconf-monitoring</artifactId>
+                <version>${netconf.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>ietf-netconf-monitoring</artifactId>
+                <version>${netconf.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.opendaylight.controller</groupId>
                 <artifactId>config-persister-api</artifactId>