Merge "removed config-util from pax-exam minimum bundles as this is not a bundle"
authorEd Warnicke <eaw@cisco.com>
Fri, 29 Nov 2013 11:19:00 +0000 (11:19 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 29 Nov 2013 11:19:00 +0000 (11:19 +0000)
132 files changed:
.gitignore
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolder.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-api/src/main/java/org/opendaylight/controller/config/persist/api/PropertiesProvider.java [new file with mode: 0644]
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/StorageAdapter.java [moved from opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/storage/StorageAdapter.java with 61% similarity]
opendaylight/config/config-persister-directory-adapter/pom.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapter.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/main/resources/footer.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/main/resources/header.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/main/resources/middle.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedCapabilities.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedSnapshot.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFile/controller.config.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config1.txt [new file with mode: 0644]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config2.txt [new file with mode: 0644]
opendaylight/config/config-persister-file-adapter/pom.xml
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/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModule.java
opendaylight/config/pom.xml
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java
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/JavaAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java
opendaylight/config/yang-test/pom.xml
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModule.java
opendaylight/config/yang-test/src/main/yang/config-test-impl.yang
opendaylight/config/yang-test/src/main/yang/types/test-types.yang [new file with mode: 0644]
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/controller-config.1.txt [new file with mode: 0644]
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/controller-config.2.txt [moved from opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config with 94% similarity]
opendaylight/distribution/opendaylight/src/main/resources/configuration/logback.xml
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/GroupConsumerImpl.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/MeterConsumerImpl.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/consumer/impl/TableFeaturesConsumerImpl.java
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-error.yang
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-service.yang
opendaylight/md-sal/model/model-flow-service/src/main/yang/group-service.yang
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/group-statistics.yang
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/meter-statistics.yang
opendaylight/md-sal/model/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java
opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/SchemaLocation.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonChoiceCaseTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/choice.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_container.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_leaflist.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_list.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_more_choices_same_level.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_no_first_case.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_random_level.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_various_path.xml [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.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/AbstractAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ArrayAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/AttributeConfigElement.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/CompositeAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/ObjectNameAttributeReadingStrategy.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/fromxml/SimpleAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleCompositeAttributeReadingStrategy.java [new file with mode: 0644]
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/attributes/toxml/SimpleAttributeWritingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleCompositeAttributeWritingStrategy.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Config.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/ModuleRuntime.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/Runtime.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-persister-impl/pom.xml
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java [new file with mode: 0644]
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/NoOpStorageAdapter.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterImpl.java [deleted file]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/PropertiesProviderBaseImpl.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterImplTest.java [deleted file]
opendaylight/netconf/config-persister-impl/src/test/resources/capabilities-all.txt [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/resources/capabilities-stripped.txt [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/resources/logback-test.xml [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/resources/snapshot.xml [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java
opendaylight/netconf/netconf-client/pom.xml
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java
opendaylight/netconf/netconf-it/pom.xml
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-it/src/test/resources/logback.xml [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/pom.xml [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/pom.xml
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/SshHandler.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/authentication/LoginPassword.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/client/SshClient.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/client/SshClientAdapter.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpc.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInner.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner.xml
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/rpcInnerInner_complex_output.xml
opendaylight/netconf/pom.xml
third-party/ganymed/pom.xml

index bb3e26faf5ee24f0f3080cbd311a87c55f7430b2..18817e7c359dbfbe526b0f37e379d859f0dfc97b 100644 (file)
@@ -19,3 +19,4 @@ opendaylight/northbound/integrationtest/logs/*
 *.iws
 .idea
 xtend-gen
+classes
index 794986a7bb7b62fd0a755da2470f53297b3f521b..a652845770eb64009bf8fc79fc63356ce99a3e95 100644 (file)
                     </goals>
                   </pluginExecutionFilter>
                   <action>
-                    <ignore />
+                     <execute>
+                      <runOnIncremental>false</runOnIncremental>
+                     </execute>
                   </action>
                 </pluginExecution>
                 <pluginExecution>
diff --git a/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolder.java b/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigSnapshotHolder.java
new file mode 100644 (file)
index 0000000..654326a
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.controller.config.persist.api;
+
+import java.util.SortedSet;
+
+public interface ConfigSnapshotHolder {
+
+        /**
+         * Get part of get-config document that contains just
+         */
+        String getConfigSnapshot();
+
+
+        /**
+         * Get only required capabilities referenced by the snapshot.
+         */
+        SortedSet<String> getCapabilities();
+    }
index f9c9301b887a1cdf36593cfeb2e0410b4a1725f1..1448e553e3017a478ee57a8e833b0ee3a9a63577 100644 (file)
@@ -10,23 +10,18 @@ package org.opendaylight.controller.config.persist.api;
 
 import com.google.common.base.Optional;
 
-import java.io.Closeable;
 import java.io.IOException;
-import java.util.Set;
 
 /**
  * Base interface for persister implementation.
  */
-public interface Persister extends Closeable {
+public interface Persister extends AutoCloseable {
 
     void persistConfig(ConfigSnapshotHolder configSnapshotHolder) throws IOException;
 
     Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException;
 
-    public static interface ConfigSnapshotHolder {
+    @Override
+    void close();
 
-        String getConfigSnapshot();
-
-        Set<String> getCapabilities();
-    }
 }
diff --git a/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/PropertiesProvider.java b/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/PropertiesProvider.java
new file mode 100644 (file)
index 0000000..1d4139f
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.api;
+
+public interface PropertiesProvider {
+    /**
+     * Get property value for given key. Implementation of this interface is allowed to prefix
+     * the key with a namespace.
+     */
+    String getProperty(String key);
+
+    /**
+     * @return prefix + key as used in getProperty method.
+     */
+    String getFullKeyForReporting(String key);
+}
@@ -6,17 +6,15 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.config.persist.api.storage;
-
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.osgi.framework.BundleContext;
+package org.opendaylight.controller.config.persist.api;
 
 /**
  * Plugins for {@link org.opendaylight.controller.config.persist.api.Persister}
  * must implement this interface.
  */
-public interface StorageAdapter extends Persister {
+public interface StorageAdapter {
+
+    Persister instantiate(PropertiesProvider propertiesProvider);
 
-    void setProperties(BundleContext bundleContext);
 
 }
diff --git a/opendaylight/config/config-persister-directory-adapter/pom.xml b/opendaylight/config/config-persister-directory-adapter/pom.xml
new file mode 100644 (file)
index 0000000..b2da71e
--- /dev/null
@@ -0,0 +1,90 @@
+<?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">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>config-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <artifactId>config-persister-directory-adapter</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <!-- compile dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>config-persister-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.bgpcep</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- workaround for creating version according to OSGi specification (major.minor.micro[.qualifier] -->
+            <plugin>
+                <groupId>org.codehaus.groovy.maven</groupId>
+                <artifactId>gmaven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>
+                                System.setProperty("osgiversion", "${project.version}".replace('-', '.'))
+                            </source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Fragment-Host>${project.groupId}.config-persister-impl;bundle-version=${osgiversion}
+                        </Fragment-Host>
+                        <Provide-Capability>org.opendaylight.controller.config.persister.storage.adapter
+                        </Provide-Capability>
+                        <Import-Package>
+                            com.google.common.base,
+                            com.google.common.io,
+                            org.apache.commons.io,
+                            org.opendaylight.controller.config.persist.api,
+                            org.slf4j
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java
new file mode 100644 (file)
index 0000000..cf4ef98
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.storage.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.Persister;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+public class DirectoryPersister implements Persister {
+    private static final Logger logger = LoggerFactory.getLogger(DirectoryPersister.class);
+    private static final Charset ENCODING = Charsets.UTF_8;
+
+    static final String MODULES_START = "//MODULES START";
+    static final String SERVICES_START = "//SERVICES START";
+    static final String CAPABILITIES_START = "//CAPABILITIES START";
+
+
+    private final File storage;
+    private final String header, middle, footer;
+
+    public DirectoryPersister(File storage) {
+        checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
+        this.storage = storage;
+        header = readResource("header.txt");
+        middle = readResource("middle.txt");
+        footer = readResource("footer.txt");
+
+    }
+
+    private static String readResource(String resource) {
+        try {
+            return IOUtils.toString(DirectoryPersister.class.getResourceAsStream("/" + resource));
+        } catch (IOException e) {
+            throw new IllegalStateException("Cannot load " + resource, e);
+        }
+    }
+
+    @Override
+    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+        throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
+    }
+
+    @Override
+    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+        File[] filesArray = storage.listFiles();
+        if (filesArray.length == 0) {
+            return Optional.absent();
+        }
+        List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
+        Collections.sort(sortedFiles);
+        // combine all found files
+
+        SortedSet<String> combinedCapabilities = new TreeSet<>();
+        StringBuilder modulesBuilder = new StringBuilder(), servicesBuilder = new StringBuilder();
+        for (File file : sortedFiles) {
+            logger.trace("Adding file '{}' to combined result", file);
+
+            final MyLineProcessor lineProcessor = new MyLineProcessor();
+            Files.readLines(file, ENCODING, lineProcessor);
+
+            modulesBuilder.append(lineProcessor.getModules());
+            servicesBuilder.append(lineProcessor.getServices());
+            combinedCapabilities.addAll(lineProcessor.getCapabilities());
+        }
+        String combinedSnapshot = header + modulesBuilder.toString() + middle + servicesBuilder.toString() + footer;
+        ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, combinedCapabilities);
+        return Optional.of(result);
+    }
+
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String toString() {
+        return "FileStorageAdapter [storage=" + storage + "]";
+    }
+}
+
+class MyLineProcessor implements com.google.common.io.LineProcessor<String> {
+
+    private boolean inModules, inServices, inCapabilities;
+    private final StringBuffer modulesBuffer = new StringBuffer(), servicesBuilder = new StringBuffer();
+    private final SortedSet<String> caps = new TreeSet<>();
+
+    @Override
+    public String getResult() {
+        return null;
+    }
+
+    @Override
+    public boolean processLine(String line) throws IOException {
+
+        String lineWithNewLine = line + System.lineSeparator();
+        if (line.equals(DirectoryPersister.MODULES_START)) {
+            checkState(inModules == false && inServices == false && inCapabilities == false);
+            inModules = true;
+        } else if (line.equals(DirectoryPersister.SERVICES_START)) {
+            checkState(inModules == true && inServices == false && inCapabilities == false);
+            inModules = false;
+            inServices = true;
+        } else if (line.equals(DirectoryPersister.CAPABILITIES_START)) {
+            checkState(inModules == false && inServices == true && inCapabilities == false);
+            inServices = false;
+            inCapabilities = true;
+        } else if (inModules) {
+            modulesBuffer.append(lineWithNewLine);
+        } else if (inServices) {
+            servicesBuilder.append(lineWithNewLine);
+        } else {
+            caps.add(line);
+        }
+        return true;
+    }
+
+    String getModules() {
+        checkState(inCapabilities);
+        return modulesBuffer.toString();
+    }
+
+    String getServices() {
+        checkState(inCapabilities);
+        return servicesBuilder.toString();
+    }
+
+    SortedSet<String> getCapabilities() {
+        checkState(inCapabilities);
+        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;
+    }
+
+    @Override
+    public SortedSet<String> getCapabilities() {
+        return caps;
+    }
+}
diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapter.java
new file mode 100644 (file)
index 0000000..69c8fba
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.persist.storage.directory;
+
+import com.google.common.base.Preconditions;
+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 java.io.File;
+
+/**
+ * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and
+ * required capabilities will be merged together. Writing to this persister is not supported.
+ */
+public class DirectoryStorageAdapter implements StorageAdapter {
+    private static final Logger logger = LoggerFactory.getLogger(DirectoryStorageAdapter.class);
+
+    public static final String DIRECTORY_STORAGE_PROP = "directoryStorage";
+
+
+    @Override
+    public Persister instantiate(PropertiesProvider propertiesProvider) {
+        String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP);
+        Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP));
+        File storage  = new File(fileStorageProperty);
+        logger.debug("Using {}", storage);
+        return new DirectoryPersister(storage);
+    }
+
+}
diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/resources/footer.txt b/opendaylight/config/config-persister-directory-adapter/src/main/resources/footer.txt
new file mode 100644 (file)
index 0000000..d4dcc62
--- /dev/null
@@ -0,0 +1,2 @@
+    </services>
+</data>
diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/resources/header.txt b/opendaylight/config/config-persister-directory-adapter/src/main/resources/header.txt
new file mode 100644 (file)
index 0000000..90ed41c
--- /dev/null
@@ -0,0 +1,2 @@
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/resources/middle.txt b/opendaylight/config/config-persister-directory-adapter/src/main/resources/middle.txt
new file mode 100644 (file)
index 0000000..f728cfd
--- /dev/null
@@ -0,0 +1,2 @@
+    </modules>
+    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java b/opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java
new file mode 100644 (file)
index 0000000..53ab4c2
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.persist.storage.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.SortedSet;
+import java.util.TreeSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+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());
+
+        try {
+            tested.persistConfig(new ConfigSnapshotHolder() {
+                @Override
+                public String getConfigSnapshot() {
+                    throw new RuntimeException();
+                }
+
+                @Override
+                public SortedSet<String> getCapabilities() {
+                    throw new RuntimeException();
+                }
+            });
+            fail();
+        } catch (UnsupportedOperationException e) {
+
+        }
+    }
+
+    private File getFolder(String folderName) {
+        File result = new File(("src/test/resources/" +
+                folderName).replace("/", File.separator));
+        assertTrue(result + " is not a directory", result.isDirectory());
+        return result;
+    }
+
+    @Test
+    public void testOneFile() throws Exception {
+        File folder = getFolder("oneFile");
+        tested = new DirectoryPersister((folder));
+        assertExpected();
+    }
+
+    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();
+    }
+
+}
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedCapabilities.txt
new file mode 100644 (file)
index 0000000..84c85b7
--- /dev/null
@@ -0,0 +1,20 @@
+urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
+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/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/expectedSnapshot.xml
new file mode 100644 (file)
index 0000000..a6a57d7
--- /dev/null
@@ -0,0 +1,103 @@
+<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>
+        <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: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>
+        <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>
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFile/controller.config.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFile/controller.config.txt
new file mode 100644 (file)
index 0000000..99b4cb9
--- /dev/null
@@ -0,0 +1,120 @@
+//MODULES START
+        <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>
+        <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>
+//SERVICES START
+        <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>
+        <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>
+//CAPABILITIES START
+urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
+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/twoFiles/controller.config1.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config1.txt
new file mode 100644 (file)
index 0000000..6ae48fb
--- /dev/null
@@ -0,0 +1,82 @@
+//MODULES START
+        <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>
+//SERVICES START
+        <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>
+//CAPABILITIES START
+urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config2.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config2.txt
new file mode 100644 (file)
index 0000000..ad9138f
--- /dev/null
@@ -0,0 +1,41 @@
+//MODULES START
+        <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>
+//SERVICES START
+        <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>
+//CAPABILITIES START
+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
index b243eadcc66ff50776ba8c00561e38bcaa649864..d34dc3770714d1141e315fdb49d8eacff04ee9d8 100644 (file)
@@ -80,7 +80,6 @@
                             javax.xml.transform.stream,
                             org.apache.commons.lang3,
                             org.opendaylight.controller.config.persist.api,
-                            org.opendaylight.controller.config.persist.api.storage,
                             org.slf4j,
                             org.w3c.dom,
                             org.xml.sax,
index 775fb1f88192cb697b38e712716851c3a246e974..66d0414d9a18485990ca709dd5ddc9832f1d4cf2 100644 (file)
@@ -12,11 +12,12 @@ import com.google.common.annotations.VisibleForTesting;
 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.apache.commons.lang3.StringUtils;
-import org.opendaylight.controller.config.persist.api.storage.StorageAdapter;
-import org.osgi.framework.BundleContext;
+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 org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.SAXException;
@@ -26,20 +27,22 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 /**
  * StorageAdapter that stores configuration in a plan file.
  */
-public class FileStorageAdapter implements StorageAdapter {
+public class FileStorageAdapter implements StorageAdapter, Persister {
     private static final Logger logger = LoggerFactory.getLogger(FileStorageAdapter.class);
 
-    // TODO prefix properties
 
     private static final Charset ENCODING = Charsets.UTF_8;
 
     public static final String FILE_STORAGE_PROP = "fileStorage";
     public static final String NUMBER_OF_BACKUPS = "numberOfBackups";
 
+
     private static final String SEPARATOR_E_PURE = "//END OF CONFIG";
     private static final String SEPARATOR_E = newLine(SEPARATOR_E_PURE);
 
@@ -55,8 +58,8 @@ public class FileStorageAdapter implements StorageAdapter {
     private File storage;
 
     @Override
-    public void setProperties(BundleContext bundleContext) {
-        File storage = extractStorageFileFromProperties(bundleContext);
+    public Persister instantiate(PropertiesProvider propertiesProvider) {
+        File storage = extractStorageFileFromProperties(propertiesProvider);
         logger.debug("Using file {}", storage.getAbsolutePath());
         // Create file if it does not exist
         File parentFile = storage.getAbsoluteFile().getParentFile();
@@ -79,7 +82,7 @@ public class FileStorageAdapter implements StorageAdapter {
                     + " property should be either set to positive value, or ommited. Can not be set to 0.");
         }
         setFileStorage(storage);
-
+        return this;
     }
 
     @VisibleForTesting
@@ -92,12 +95,11 @@ public class FileStorageAdapter implements StorageAdapter {
         numberOfStoredBackups = numberOfBackups;
     }
 
-    private static File extractStorageFileFromProperties(BundleContext bundleContext) {
-        String fileStorageProperty = bundleContext.getProperty(FILE_STORAGE_PROP);
-        Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + FILE_STORAGE_PROP
-                + " in received context :" + bundleContext);
+    private static File extractStorageFileFromProperties(PropertiesProvider propertiesProvider) {
+        String fileStorageProperty = propertiesProvider.getProperty(FILE_STORAGE_PROP);
+        Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(FILE_STORAGE_PROP));
         File result = new File(fileStorageProperty);
-        String numberOfBAckupsAsString = bundleContext.getProperty(NUMBER_OF_BACKUPS);
+        String numberOfBAckupsAsString = propertiesProvider.getProperty(NUMBER_OF_BACKUPS);
         if (numberOfBAckupsAsString != null) {
             numberOfStoredBackups = Integer.valueOf(numberOfBAckupsAsString);
         } else {
@@ -189,7 +191,7 @@ public class FileStorageAdapter implements StorageAdapter {
 
         private boolean inLastConfig, inLastSnapshot;
         private final StringBuffer snapshotBuffer = new StringBuffer();
-        private final Set<String> caps = Sets.newHashSet();
+        private final SortedSet<String> caps = new TreeSet<>();
 
         @Override
         public String getResult() {
@@ -233,14 +235,14 @@ public class FileStorageAdapter implements StorageAdapter {
                 return Optional.of(xmlContent);
         }
 
-        Set<String> getCapabilities() throws IOException, SAXException, ParserConfigurationException {
+        SortedSet<String> getCapabilities() throws IOException, SAXException, ParserConfigurationException {
             return caps;
         }
 
     }
 
     @Override
-    public void close() throws IOException {
+    public void close() {
 
     }
 
@@ -252,9 +254,9 @@ public class FileStorageAdapter implements StorageAdapter {
     private class PersistedConfigImpl implements ConfigSnapshotHolder {
 
         private final String snapshot;
-        private final Set<String> caps;
+        private final SortedSet<String> caps;
 
-        public PersistedConfigImpl(Optional<String> configSnapshot, Set<String> capabilities) {
+        public PersistedConfigImpl(Optional<String> configSnapshot, SortedSet<String> capabilities) {
             this.snapshot = configSnapshot.get();
             this.caps = capabilities;
         }
@@ -265,7 +267,7 @@ public class FileStorageAdapter implements StorageAdapter {
         }
 
         @Override
-        public Set<String> getCapabilities() {
+        public SortedSet<String> getCapabilities() {
             return caps;
         }
     }
index c7d37dcbd8c65b3cea42541943ebf3d8eae0870d..ed50184aa7ad50d7e825fa6df2895271a99be834 100644 (file)
@@ -12,17 +12,16 @@ 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 com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
-import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 
 import java.io.File;
 import java.nio.file.Files;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -49,14 +48,14 @@ public class FileStorageAdapterTest {
         FileStorageAdapter storage = new FileStorageAdapter();
         storage.setFileStorage(file);
         storage.setNumberOfBackups(Integer.MAX_VALUE);
-        final Persister.ConfigSnapshotHolder holder = new Persister.ConfigSnapshotHolder() {
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
             @Override
             public String getConfigSnapshot() {
                 return createConfig();
             }
 
             @Override
-            public Set<String> getCapabilities() {
+            public SortedSet<String> getCapabilities() {
                 return createCaps();
             }
         };
@@ -76,15 +75,15 @@ public class FileStorageAdapterTest {
                 });
         assertEquals(14, readLines.size());
 
-        Optional<Persister.ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
+        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
         assertTrue(lastConf.isPresent());
         assertEquals("<config>2</config>",
                 lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
         assertEquals(createCaps(), lastConf.get().getCapabilities());
     }
 
-    private Set<String> createCaps() {
-        Set<String> caps = Sets.newHashSet();
+    private SortedSet<String> createCaps() {
+        SortedSet<String> caps = new TreeSet<>();
 
         caps.add("cap1");
         caps.add("cap2");
@@ -97,14 +96,14 @@ public class FileStorageAdapterTest {
         FileStorageAdapter storage = new FileStorageAdapter();
         storage.setFileStorage(file);
         storage.setNumberOfBackups(1);
-        final Persister.ConfigSnapshotHolder holder = new Persister.ConfigSnapshotHolder() {
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
             @Override
             public String getConfigSnapshot() {
                 return createConfig();
             }
 
             @Override
-            public Set<String> getCapabilities() {
+            public SortedSet<String> getCapabilities() {
                 return createCaps();
             }
         };
@@ -124,7 +123,7 @@ public class FileStorageAdapterTest {
                 });
         assertEquals(7, readLines.size());
 
-        Optional<Persister.ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
+        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
         assertTrue(lastConf.isPresent());
         assertEquals("<config>2</config>",
                 lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
@@ -135,14 +134,14 @@ public class FileStorageAdapterTest {
         FileStorageAdapter storage = new FileStorageAdapter();
         storage.setFileStorage(file);
         storage.setNumberOfBackups(2);
-        final Persister.ConfigSnapshotHolder holder = new Persister.ConfigSnapshotHolder() {
+        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
             @Override
             public String getConfigSnapshot() {
                 return createConfig();
             }
 
             @Override
-            public Set<String> getCapabilities() {
+            public SortedSet<String> getCapabilities() {
                 return createCaps();
             }
         };
@@ -164,7 +163,7 @@ public class FileStorageAdapterTest {
 
         assertEquals(14, readLines.size());
 
-        Optional<Persister.ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
+        Optional<ConfigSnapshotHolder> lastConf = storage.loadLastConfig();
         assertTrue(lastConf.isPresent());
         assertEquals("<config>3</config>",
                lastConf.get().getConfigSnapshot().replaceAll("\\s", ""));
@@ -179,7 +178,7 @@ public class FileStorageAdapterTest {
         FileStorageAdapter storage = new FileStorageAdapter();
         storage.setFileStorage(file);
 
-        Optional<Persister.ConfigSnapshotHolder> elementOptional = storage.loadLastConfig();
+        Optional<ConfigSnapshotHolder> elementOptional = storage.loadLastConfig();
         assertThat(elementOptional.isPresent(), is(false));
     }
 
@@ -192,15 +191,15 @@ public class FileStorageAdapterTest {
     @Test(expected = NullPointerException.class)
     public void testNoProperties2() throws Exception {
         FileStorageAdapter storage = new FileStorageAdapter();
-        storage.persistConfig(new Persister.ConfigSnapshotHolder() {
+        storage.persistConfig(new ConfigSnapshotHolder() {
             @Override
             public String getConfigSnapshot() {
                 return Mockito.mock(String.class);
             }
 
             @Override
-            public Set<String> getCapabilities() {
-                return Collections.<String> emptySet();
+            public SortedSet<String> getCapabilities() {
+                return new TreeSet<>();
             }
         } );
     }
index 205f123b1de6e28cea70fbb6bacac91b9162d2fb..02fba141b338872fe6a1fefa473d56110f9777d8 100644 (file)
@@ -101,13 +101,15 @@ public class ContextSetterImpl implements ContextSetter, Closeable {
 
     private void addNewAppenders(Map<String, Appender<ILoggingEvent>> appendersMap, LoggerTO logger,
             ch.qos.logback.classic.Logger logbackLogger, Optional<Set<Appender<ILoggingEvent>>> appendersBefore) {
-        for (String appenderName : logger.getAppenders()) {
-            if (appendersMap.containsKey(appenderName)) {
-                logbackLogger.addAppender(appendersMap.get(appenderName));
-                classLogger.trace("Logger {}: Adding new appender: {}", logger.getLoggerName(), appenderName);
-            } else {
-                throw new IllegalStateException("No appender " + appenderName
-                        + " found. This error should have been discovered by validation");
+        if (logger.getAppenders() != null) {
+            for (String appenderName : logger.getAppenders()) {
+                if (appendersMap.containsKey(appenderName)) {
+                    logbackLogger.addAppender(appendersMap.get(appenderName));
+                    classLogger.trace("Logger {}: Adding new appender: {}", logger.getLoggerName(), appenderName);
+                } else {
+                    throw new IllegalStateException("No appender " + appenderName
+                            + " found. This error should have been discovered by validation");
+                }
             }
         }
     }
index 9cbcd47b20dbe48cc6cfacdade3d50a8c3ed474e..d75bf6367a6d393d7ee2773a5d903733ae2b21aa 100644 (file)
@@ -54,11 +54,12 @@ public final class LogbackModule extends org.opendaylight.controller.config.yang
                     "LoggerName needs to be set", loggersJmxAttribute);
             JmxAttributeValidationException.checkCondition(!loggerToValidate.getLevel().isEmpty(),
                     "Level needs to be set", loggersJmxAttribute);
-
-            for (String appenderName : loggerToValidate.getAppenders()) {
-                JmxAttributeValidationException.checkCondition(appenderNames.contains(appenderName), "Appender "
-                        + appenderName + " referenced by logger " + loggerToValidate.getLoggerName()
-                        + " not present in configuration, present appenders: " + appenderNames, loggersJmxAttribute);
+            if (loggerToValidate.getAppenders() != null) {
+                for (String appenderName : loggerToValidate.getAppenders()) {
+                    JmxAttributeValidationException.checkCondition(appenderNames.contains(appenderName), "Appender "
+                            + appenderName + " referenced by logger " + loggerToValidate.getLoggerName()
+                            + " not present in configuration, present appenders: " + appenderNames, loggersJmxAttribute);
+                }
             }
 
         }
index 22be6f162b23239cf4952ec6283ae0094d3e0e74..c1eef701da271014a5777f098926562a54a45074 100644 (file)
@@ -35,6 +35,7 @@
         <module>netty-threadgroup-config</module>
         <module>netty-event-executor-config</module>
         <module>netty-timer-config</module>
+        <module>config-persister-directory-adapter</module>
     </modules>
 
     <profiles>
index 7490ad60847aaa45728d0b627a3091ff2d7a3fb7..a2238d1a13da854c07df8278c697e8fddd15bdd2 100644 (file)
@@ -11,6 +11,8 @@ import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 
 public class TypeProviderWrapper {
     private final TypeProvider typeProvider;
@@ -20,10 +22,15 @@ public class TypeProviderWrapper {
     }
 
     public Type getType(LeafSchemaNode leaf) {
+        TypeDefinition<?> type = leaf.getType();
+        return getType(leaf, type);
+    }
+
+    public Type getType(SchemaNode leaf, TypeDefinition<?> type) {
         Type javaType;
         try {
             javaType = typeProvider.javaTypeForSchemaDefinitionType(
-                    leaf.getType(), leaf);
+                    type, leaf);
             if (javaType == null)
                 throw new IllegalArgumentException("Unknown type received for "
                         + leaf.toString());
@@ -50,4 +57,7 @@ public class TypeProviderWrapper {
         return javaType;
     }
 
+    public String getJMXParamForBaseType(TypeDefinition<?> baseType) {
+        return typeProvider.getConstructorPropertyName(baseType);
+    }
 }
index 5ffc19213746ce9cbbe5ca9ccb6ae38542cbf1f5..ba2edc4e31d867f1304a0108400cd41e2b7b43de 100644 (file)
@@ -13,7 +13,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 public abstract class AbstractAttribute implements AttributeIfc {
     private final String attributeYangName, upperCaseCammelCase,
             lowerCaseCammelCase;
-    private final DataSchemaNode node;
+    protected final DataSchemaNode node;
 
     private static String getLocalName(DataSchemaNode attrNode) {
         return attrNode.getQName().getLocalName();
index b6d60e40417dcb9b3301888e46cd20518afc9097..1912b75e0ee740c31634c2e709650a7d0c33728a 100644 (file)
@@ -7,15 +7,14 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.attribute;
 
-import javax.management.ObjectName;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
 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.SimpleType;
+
 public class DependencyAttribute extends AbstractAttribute implements
         TypedAttribute {
 
@@ -95,7 +94,7 @@ public class DependencyAttribute extends AbstractAttribute implements
     }
 
     @Override
-    public OpenType<?> getOpenType() {
+    public SimpleType<?> getOpenType() {
         return SimpleType.OBJECTNAME;
     }
 
index 59ab0ff68ea6efa133c2cee357724ed21ac40db8..325ca9ee06fd1bd9d29d56a94cedc0871aac77c7 100644 (file)
@@ -11,8 +11,10 @@ import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 
 import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.OpenDataException;
 import javax.management.openmbean.OpenType;
 import javax.management.openmbean.SimpleType;
@@ -21,11 +23,15 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
 
     private final Type type;
     private final String nullableDescription, nullableDefault;
+    private final TypeProviderWrapper typeProviderWrapper;
+    private final TypeDefinition<?> typeDefinition;
 
     public JavaAttribute(LeafSchemaNode leaf,
             TypeProviderWrapper typeProviderWrapper) {
         super(leaf);
         this.type = typeProviderWrapper.getType(leaf);
+        this.typeDefinition = leaf.getType();
+        this.typeProviderWrapper = typeProviderWrapper;
         this.nullableDefault = leaf.getDefault();
         this.nullableDescription = leaf.getDescription();
     }
@@ -34,10 +40,22 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
             TypeProviderWrapper typeProviderWrapper) {
         super(leaf);
         this.type = typeProviderWrapper.getType(leaf);
+        this.typeDefinition = leaf.getType();
+        this.typeProviderWrapper = typeProviderWrapper;
         this.nullableDefault = null;
         this.nullableDescription = leaf.getDescription();
     }
 
+    /**
+     * Returns the most base type
+     */
+    private TypeDefinition<?> getBaseType(TypeProviderWrapper typeProviderWrapper, TypeDefinition<?> baseType) {
+        while(baseType.getBaseType()!=null) {
+            baseType = baseType.getBaseType();
+        }
+        return baseType;
+    }
+
     @Override
     public Type getType() {
         return type;
@@ -98,27 +116,60 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
 
     @Override
     public OpenType<?> getOpenType() {
-        // If is array => arrayType
-        if (isArray(getType())) {
-            String innerTypeFullyQName = getInnerType(getType());
-            SimpleType<?> innerSimpleType = SimpleTypeResolver
-                    .getSimpleType(innerTypeFullyQName);
-            try {
-                ArrayType<Object> arrayType = isPrimitive(innerTypeFullyQName) ? new ArrayType<>(
-                        innerSimpleType, true) : new ArrayType<>(1,
-                        innerSimpleType);
-                return arrayType;
-            } catch (OpenDataException e) {
-                throw new RuntimeException("Unable to create "
-                        + ArrayType.class + " with inner element of type "
-                        + innerSimpleType, e);
-            }
+        TypeDefinition<?> baseTypeDefinition = getBaseType(typeProviderWrapper, typeDefinition);
+        Type baseType = typeProviderWrapper.getType(baseTypeDefinition, baseTypeDefinition);
+
+        if (isArray()) {
+            return getArrayType();
+        } else if (isEnum(baseType)) {
+            return getSimpleType(baseType);
+        } else if (isDerivedType(baseType)) {
+            return getCompositeType(baseType, baseTypeDefinition);
         }
-        // else simple type
-        SimpleType<?> simpleType = SimpleTypeResolver.getSimpleType(getType());
+
+        return getSimpleType(getType());
+    }
+
+    private boolean isEnum(Type baseType) {
+        return baseType.getFullyQualifiedName().equals(Enum.class.getName());
+    }
+
+    private OpenType<?> getSimpleType(Type type) {
+        SimpleType<?> simpleType = SimpleTypeResolver.getSimpleType(type);
         return simpleType;
     }
 
+     private OpenType<?> getCompositeType(Type baseType, TypeDefinition<?> baseTypeDefinition) {
+
+        SimpleType<?> innerItemType = SimpleTypeResolver.getSimpleType(baseType);
+        String innerItemName = typeProviderWrapper.getJMXParamForBaseType(baseTypeDefinition);
+
+        String[] itemNames = new String[]{innerItemName};
+        String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
+
+        OpenType<?>[] itemTypes = new OpenType[]{innerItemType};
+        try {
+            return new CompositeType(getUpperCaseCammelCase(), description, itemNames, itemNames, itemTypes);
+        } catch (OpenDataException e) {
+            throw new RuntimeException("Unable to create " + CompositeType.class + " with inner element of type "
+                    + itemTypes, e);
+        }
+
+    }
+
+    private OpenType<?> getArrayType() {
+        String innerTypeFullyQName = getInnerType(getType());
+        SimpleType<?> innerSimpleType = SimpleTypeResolver.getSimpleType(innerTypeFullyQName);
+        try {
+            ArrayType<Object> arrayType = isPrimitive(innerTypeFullyQName) ? new ArrayType<>(innerSimpleType, true)
+                    : new ArrayType<>(1, innerSimpleType);
+            return arrayType;
+        } catch (OpenDataException e) {
+            throw new RuntimeException("Unable to create " + ArrayType.class + " with inner element of type "
+                    + innerSimpleType, e);
+        }
+    }
+
     // TODO verify
     private boolean isPrimitive(String innerTypeFullyQName) {
         if (innerTypeFullyQName.contains("."))
@@ -127,13 +178,17 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
         return true;
     }
 
+    private boolean isArray() {
+        return type.getName().endsWith("[]");
+    }
+
+    private boolean isDerivedType(Type baseType) {
+        return  baseType.equals(getType()) == false;
+    }
+
     private static String getInnerType(Type type) {
         String fullyQualifiedName = type.getFullyQualifiedName();
         return fullyQualifiedName.substring(0, fullyQualifiedName.length() - 2);
     }
 
-    private static boolean isArray(Type type) {
-        return type.getName().endsWith("[]");
-    }
-
 }
index 349459a93167c9158976624a6bfb803410825f58..87b55f3756a0e042c98c89739d91bf0f92ab5285 100644 (file)
@@ -7,18 +7,16 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.attribute;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+
+import javax.management.openmbean.SimpleType;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Date;
 import java.util.Map;
 
-import javax.management.openmbean.SimpleType;
-
-import org.opendaylight.yangtools.sal.binding.model.api.Type;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-
 public class SimpleTypeResolver {
 
     public static SimpleType<?> getSimpleType(Type type) {
@@ -29,6 +27,10 @@ public class SimpleTypeResolver {
         return expectedSimpleType;
     }
 
+    public static boolean canResolve(Type type) {
+        return JAVA_TYPE_TO_SIMPLE_TYPE.containsKey(type.getFullyQualifiedName());
+    }
+
     public static SimpleType<?> getSimpleType(String fullyQualifiedName) {
         SimpleType<?> expectedSimpleType = JAVA_TYPE_TO_SIMPLE_TYPE
                 .get(fullyQualifiedName);
@@ -37,26 +39,21 @@ public class SimpleTypeResolver {
         return expectedSimpleType;
     }
 
-    private static final Map<String, SimpleType<?>> JAVA_TYPE_TO_SIMPLE_TYPE = Maps
-            .newHashMap();
+    private static final Map<String, SimpleType<?>> JAVA_TYPE_TO_SIMPLE_TYPE = Maps.newHashMap();
     static {
         // TODO add all
-        JAVA_TYPE_TO_SIMPLE_TYPE.put(Integer.class.getName(),
-                SimpleType.INTEGER);
+        JAVA_TYPE_TO_SIMPLE_TYPE.put(Integer.class.getName(), SimpleType.INTEGER);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(int.class.getName(), SimpleType.INTEGER);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(Short.class.getName(), SimpleType.SHORT);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(short.class.getName(), SimpleType.SHORT);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(Long.class.getName(), SimpleType.LONG);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(long.class.getName(), SimpleType.LONG);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(String.class.getName(), SimpleType.STRING);
-        JAVA_TYPE_TO_SIMPLE_TYPE.put(Boolean.class.getName(),
-                SimpleType.BOOLEAN);
-        JAVA_TYPE_TO_SIMPLE_TYPE.put(boolean.class.getName(),
-                SimpleType.BOOLEAN);
-        JAVA_TYPE_TO_SIMPLE_TYPE.put(BigInteger.class.getName(),
-                SimpleType.BIGINTEGER);
-        JAVA_TYPE_TO_SIMPLE_TYPE.put(BigDecimal.class.getName(),
-                SimpleType.BIGDECIMAL);
+        JAVA_TYPE_TO_SIMPLE_TYPE.put(Enum.class.getName(), SimpleType.STRING);
+        JAVA_TYPE_TO_SIMPLE_TYPE.put(Boolean.class.getName(), SimpleType.BOOLEAN);
+        JAVA_TYPE_TO_SIMPLE_TYPE.put(boolean.class.getName(), SimpleType.BOOLEAN);
+        JAVA_TYPE_TO_SIMPLE_TYPE.put(BigInteger.class.getName(), SimpleType.BIGINTEGER);
+        JAVA_TYPE_TO_SIMPLE_TYPE.put(BigDecimal.class.getName(), SimpleType.BIGDECIMAL);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(Byte.class.getName(), SimpleType.BYTE);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(byte.class.getName(), SimpleType.BYTE);
         JAVA_TYPE_TO_SIMPLE_TYPE.put(Date.class.getName(), SimpleType.DATE);
index 20029d06f9cd40e691bd97be33fcf3645736aef8..96656338df130f30ef569fbb54537727ff9a0b3a 100644 (file)
@@ -7,15 +7,10 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.attribute;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenDataException;
-import javax.management.openmbean.OpenType;
-
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+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.yang.model.api.AugmentationTarget;
@@ -26,10 +21,13 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 
 public class TOAttribute extends AbstractAttribute {
 
@@ -59,7 +57,7 @@ public class TOAttribute extends AbstractAttribute {
                         createInnerAttribute(dataSchemaNode,
                                 typeProviderWrapper));
             } catch (IllegalArgumentException e) {
-                throw new IllegalStateException("Unable to create TO");
+                throw new IllegalStateException("Unable to create TO", e);
             }
         }
         return new TOAttribute(containerSchemaNode, map, attributeNameMap,
@@ -200,7 +198,7 @@ public class TOAttribute extends AbstractAttribute {
     }
 
     @Override
-    public OpenType<?> getOpenType() {
+    public CompositeType getOpenType() {
         String description = getNullableDescription() == null ? getAttributeYangName()
                 : getNullableDescription();
         final String[] itemNames = new String[yangNameToAttributeMap.keySet()
index b7540c8787b15b499d9542e46998de0c32cfa2e2..f8d86b28bb2033f25874754acbfff2fdde4080b5 100644 (file)
         </dependency>
     </dependencies>
 
-
-
     <build>
         <plugins>
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
+                <version>${opendaylight.yang.version}</version>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+
+                    <execution>
+                        <id>types</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang/types</yangFilesRootDir>
+                            <codeGenerators>
+                              <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        target/generated-sources/sal
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.binding.version}</version>
+                    </dependency>
+                </dependencies>
             </plugin>
         </plugins>
     </build>
index 43f6200ac415d76cd48abdac6aa75ea952426c2a..ae86d42d8ebd18458aa69f80d47024bbbdd4c131 100644 (file)
 package org.opendaylight.controller.config.yang.test.impl;
 
 
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
 /**
 *
 */
@@ -38,11 +42,118 @@ public final class NetconfTestImplModule
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new AutoCloseable() {
+        return registerRuntimeBeans();
+    }
+
+    private NetconfTestImplRuntimeRegistration registerRuntimeBeans() {
+        NetconfTestImplRuntimeRegistration reg = getRootRuntimeBeanRegistratorWrapper().register(new NetconfTestImplRuntimeMXBean() {
+
+            @Override
+            public Long getCreatedSessions() {
+                return getSimpleLong();
+            }
+
             @Override
-            public void close() throws Exception {
+            public Asdf getAsdf() {
+                final Asdf asdf = new Asdf();
+                asdf.setSimpleString("asdf");
+                return asdf;
             }
-        };
+
+            @Override
+            public String noArg(final String arg1) {
+                return arg1.toUpperCase();
+            }
+
+        });
+
+        for (int i = 0; i < getSimpleShort(); i++) {
+            final int finalI = i;
+
+            reg.register(new InnerRunningDataAdditionalRuntimeMXBean() {
+                @Override
+                public Integer getSimpleInt3() {
+                    return getSimpleTest();
+                }
+
+                @Override
+                public Deep4 getDeep4() {
+                    final Deep4 d = new Deep4();
+                    d.setBoool(false);
+                    return d;
+                }
+
+                @Override
+                public String getSimpleString() {
+                    return Integer.toString(finalI);
+                }
+
+                @Override
+                public void noArgInner() {
+                }
+            });
+
+            InnerRunningDataRuntimeRegistration innerReg = reg.register(new InnerRunningDataRuntimeMXBean() {
+                @Override
+                public Integer getSimpleInt3() {
+                    return finalI;
+                }
+
+                @Override
+                public Deep2 getDeep2() {
+                    return new Deep2();
+                }
+            });
+
+            for (int j = 0; j < getSimpleShort(); j++) {
+                final int finalJ = j;
+                innerReg.register(new InnerInnerRunningDataRuntimeMXBean() {
+                    @Override
+                    public List<NotStateBean> getNotStateBean() {
+                        NotStateBean b1 = new NotStateBean();
+                        b1.setElement("not state");
+                        return Lists.newArrayList(b1);
+                    }
+
+                    @Override
+                    public Integer getSimpleInt3() {
+                        return finalJ;
+                    }
+
+                    @Override
+                    public Deep3 getDeep3() {
+                        return new Deep3();
+                    }
+
+                    @Override
+                    public List<String> getListOfStrings() {
+                        return Lists.newArrayList("l1", "l2");
+                    }
+
+                    @Override
+                    public List<RetValList> listOutput() {
+                        return Lists.newArrayList(new RetValList());
+                    }
+
+                    @Override
+                    public Boolean noArgInnerInner(Integer integer, Boolean aBoolean) {
+                        return aBoolean;
+                    }
+
+                    @Override
+                    public RetValContainer containerOutput() {
+                        return new RetValContainer();
+                    }
+
+                    @Override
+                    public List<String> leafListOutput() {
+                        return Lists.newArrayList("1", "2");
+                    }
+                });
+            }
+        }
+
+        return reg;
     }
 
 }
index 291e3ebd948159d2a6191e6ca31d8452987486da..df636fd0ef3297eb3f87870afa38d8cd18098cf5 100644 (file)
@@ -7,7 +7,7 @@ module config-test-impl {
     import config { prefix config; revision-date 2013-04-05; }
     import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
     import rpc-context { prefix rpcx; revision-date 2013-06-17; }
-
+    import test-types { prefix tt; revision-date 2013-11-27; }
 
     description
         "Testing IMPL";
@@ -107,6 +107,18 @@ module config-test-impl {
                 type string;
             }
 
+            leaf extended {
+                type tt:extend-once;
+            }
+
+            leaf extended-twice {
+                type tt:extend-twice;
+            }
+
+            leaf extended-enum {
+                type tt:extend-enum;
+            }
+
            container dto-c {
                 leaf simple-arg {
                     type uint32;
diff --git a/opendaylight/config/yang-test/src/main/yang/types/test-types.yang b/opendaylight/config/yang-test/src/main/yang/types/test-types.yang
new file mode 100644 (file)
index 0000000..84fbcb0
--- /dev/null
@@ -0,0 +1,26 @@
+module test-types {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:test:types";
+    prefix "tt";
+
+    description
+        "Types generated for testing";
+
+    revision "2013-11-27";
+
+    typedef extend-once {
+        type uint16;
+    }
+
+    typedef extend-twice {
+        type extend-once;
+    }
+
+    typedef extend-enum {
+        type enumeration {
+            enum "ONE";
+            enum "TWO";
+        }
+    }
+
+}
index 5b08af79f835e39b0d729424d31cf522ea78c256..d1b1e736365aaff9ed9aad9ebcafee77083b58a4 100644 (file)
           <artifactId>config-persister-file-adapter</artifactId>
           <version>${config.version}</version>
         </dependency>
-
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>config-persister-directory-adapter</artifactId>
+              <version>${config.version}</version>
+          </dependency>
 
        <!-- Netconf -->
         <dependency>
           <artifactId>netconf-mapping-api</artifactId>
           <version>${netconf.version}</version>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>netconf-ssh</artifactId>
+          <version>${netconf.version}</version>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>config-netconf-connector</artifactId>
           <groupId>org.opendaylight.yangtools</groupId>
           <artifactId>yang-model-api</artifactId>
          </dependency>
-
          <dependency>
           <groupId>org.opendaylight.yangtools.model</groupId>
           <artifactId>yang-ext</artifactId>
          </dependency>
-
         <dependency>
          <groupId>org.opendaylight.controller.thirdparty</groupId>
          <artifactId>ganymed</artifactId>
index bfc3962040de008313256355ae917948d0caf5e4..b5bdb9e903d64e5a490b7f1e4f0530613d46e96c 100644 (file)
@@ -17,14 +17,19 @@ osgi.bundles=\
 netconf.tcp.address=0.0.0.0
 netconf.tcp.port=8383
 
-#netconf.tls.address=127.0.0.1
-#netconf.tls.port=8384
-#netconf.tls.keystore=
-#netconf.tls.keystore.password=
-
-netconf.config.persister.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
-fileStorage=configuration/controller.config
-numberOfBackups=1
+netconf.ssh.address=0.0.0.0
+netconf.ssh.port=1830
+
+netconf.config.persister.active=1,2
+# read startup configuration
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+netconf.config.persister.1.properties.directoryStorage=configuration/initial/
+netconf.config.persister.1.readonly=true
+
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.txt
+
+
 yangstore.blacklist=.*controller.model.*
 
 # Set Default start level for framework
diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/controller-config.1.txt b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/controller-config.1.txt
new file mode 100644 (file)
index 0000000..689b45a
--- /dev/null
@@ -0,0 +1,5 @@
+//MODULES START
+//SERVICES START
+
+//CAPABILITIES START
+urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16
similarity index 94%
rename from opendaylight/distribution/opendaylight/src/main/resources/configuration/controller.config
rename to opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/controller-config.2.txt
index 947c15b35c27f19a5566f32849a33ab440982c70..acae8866cee17788f73ed482f3723775f2069ace 100644 (file)
@@ -1,6 +1,4 @@
-//START OF CONFIG-LAST
-<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
-<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+//MODULES START
        <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>
@@ -49,8 +47,7 @@
                <name>ref_runtime-mapping-singleton</name>
                </mapping-service>
        </module>
-</modules>
-<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+//SERVICES START
        <service>
        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
                <instance>
                <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
        </instance>
        </service>
-</services>
-</data>
-
-//END OF SNAPSHOT
+//CAPABILITIES START
 urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
 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
@@ -119,9 +113,7 @@ 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
-//END OF CONFIG
index 3ad0c61d4f66ffb8763354e65bc2d196d88929df..2815422274fad3c61cfa95ba724969eadf30d001 100644 (file)
@@ -36,7 +36,6 @@
   <!--  Base log level  -->
   <logger name="org.opendaylight" level="INFO"/>
 
-  <logger name="org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort" level="ERROR"/>
 
   <!-- Controller log level -->
   <logger name="org.opendaylight.controller" level="INFO"/>
index 714ac89ba13ccf66f3de6e211276d2aace61aba9..b8dac19bf37956262e9b88a35f24b95b719edc5c 100644 (file)
@@ -73,8 +73,7 @@ public class GroupConsumerImpl implements IForwardingRulesManager {
 
     public GroupConsumerImpl() {
 
-        InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Groups.class).child(Group.class)
-                .toInstance();
+        InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Groups.class).toInstance();
         groupService = FRMConsumerImpl.getProviderSession().getRpcService(SalGroupService.class);
 
         clusterGroupContainerService = FRMConsumerImpl.getClusterContainerService();
index 483b9a47196580a2b16c9e0c63b2e41be7a40e9f..cef259b395629a8681bf748d4f54fdf8761d84c7 100644 (file)
@@ -73,8 +73,7 @@ public class MeterConsumerImpl implements IForwardingRulesManager {
     
 
     public MeterConsumerImpl() {
-        InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).child(Meter.class)
-                .toInstance();
+        InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Meters.class).toInstance();
         meterService = FRMConsumerImpl.getProviderSession().getRpcService(SalMeterService.class);
         clusterMeterContainerService = FRMConsumerImpl.getClusterContainerService();
 
index 30556e47141c8825eebb3d2cda7c29a94cfcb387..11d1189573244abad3c5bdac9f231065737a4da4 100644 (file)
@@ -37,8 +37,7 @@ public class TableFeaturesConsumerImpl {
     private boolean inContainerMode; // being used by global instance only
 
     public TableFeaturesConsumerImpl() {
-        InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Tables.class).child(Table.class)
-                .toInstance();
+        InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Tables.class).toInstance();
         tableService = FRMConsumerImpl.getProviderSession().getRpcService(SalTableService.class);
 
         if (null == tableService) {
@@ -115,12 +114,14 @@ public class TableFeaturesConsumerImpl {
         }
 
         Map<InstanceIdentifier<?>, TableFeatures> updates = new HashMap<>();
+        Map<InstanceIdentifier<?>, TableFeatures> createdEntries = new HashMap<>();
 
         /**
          * We create a plan which table features will be updated.
          *
          */
         void prepareUpdate() {
+               Set<Entry<InstanceIdentifier<?>, DataObject>> createdEntries = modification.getCreatedConfigurationData().entrySet();
 
             Set<Entry<InstanceIdentifier<?>, DataObject>> puts = modification.getUpdatedConfigurationData().entrySet();
             for (Entry<InstanceIdentifier<?>, DataObject> entry : puts) {
index 369b279b95264a317ae51001f016290bbdac79cb..3e9d1ee75fe9644def39f3077c9b3d3c7d328f03 100644 (file)
@@ -16,7 +16,7 @@ module flow-errors {
             enum flow-mod-failed;
             enum group-mod-failed;
             enum port-mod-failed;
-            enum table-mod-failed;            
+            enum table-mod-failed;
             enum queue-op-failed;
             enum switch-config-failed;
             enum role-request-failed;
@@ -34,7 +34,7 @@ module flow-errors {
         }
         
         leaf code {
-            type uint16;        
+            type uint16;
         }
         
         leaf data {
@@ -48,15 +48,15 @@ module flow-errors {
         }
         
         leaf exp-type {
-            type uint16;        
+            type uint16;
         }
         
         leaf experimenter-id {
-            type uint32;        
+            type uint32;
         }
         
         leaf data {
             type string;
         }
-    }   
+    }
 }
\ No newline at end of file
index a32a45f2fdfea5cb5ce894c9c569942e0752d48e..07678f57e1b429d8655fa3665d26eaa9c83f74d8 100644 (file)
@@ -52,7 +52,7 @@ module sal-flow {
     rpc add-flow {
         input {
             uses node-flow;
-            uses tr:transaction-aware;            
+            uses tr:transaction-aware;
         }
         output {
             uses tr:transaction-aware;
@@ -62,7 +62,7 @@ module sal-flow {
     rpc remove-flow {
         input {
             uses node-flow;
-            uses tr:transaction-aware;            
+            uses tr:transaction-aware;
         }
         output {
             uses tr:transaction-aware;
@@ -72,7 +72,7 @@ module sal-flow {
     rpc update-flow {
         input {
             uses flow-update;
-            uses tr:transaction-aware;            
+            uses tr:transaction-aware;
         }
         output {
             uses tr:transaction-aware;
index b21423b7d4d94d6db1a850a3cbac99bf5547a2d3..9106bca8a4826619f09062a3c3322b16e3551621 100644 (file)
@@ -32,7 +32,7 @@ module sal-group {
     rpc add-group {
         input {
             uses node-group;
-            uses tr:transaction-aware;            
+            uses tr:transaction-aware;
         }
         output {
             uses tr:transaction-aware;
@@ -42,7 +42,7 @@ module sal-group {
     rpc remove-group {
         input {
             uses node-group;
-            uses tr:transaction-aware;            
+            uses tr:transaction-aware;
         }
         output {
             uses tr:transaction-aware;
@@ -52,7 +52,7 @@ module sal-group {
     rpc update-group {
         input {
             uses group-update;
-            uses tr:transaction-aware;            
+            uses tr:transaction-aware;
         }
         output {
             uses tr:transaction-aware;
index d29ddc0ddd68bcef17b84cfec9ac92eab6d5cc24..1b6a9df9ad514fbccdf4fb0d7de043421e968e4c 100644 (file)
@@ -8,9 +8,9 @@ module opendaylight-group-statistics {
     import flow-capable-transaction {prefix tr;}
     
     contact
-       "Anilkumar Vishnoi
-       Email: avishnoi@in.ibm.com";
-               
+        "Anilkumar Vishnoi
+        Email: avishnoi@in.ibm.com";
+            
     revision "2013-11-11" {
         description "Initial revision of group statistics service";
     }
@@ -18,44 +18,44 @@ module opendaylight-group-statistics {
     augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-group-statistics";
         container group-statistics {
-               //config "false";
-               uses group-types:group-statistics-reply;
+            //config "false";
+            uses group-types:group-statistics-reply;
         }
     }
 
-       augment "/inv:nodes/inv:node" {
+    augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-group-desc-stats";
         container group-desc {
-               //config "false";
-               uses group-types:group-desc-stats-reply;
+            //config "false";
+            uses group-types:group-desc-stats-reply;
         }
     }
-       
-       augment "/inv:nodes/inv:node" {
+    
+    augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-group-features";
         container group-features {
-               //config "false";
-               uses group-types:group-features-reply;
+            //config "false";
+            uses group-types:group-features-reply;
         }
     }
 
-       // RPC calls
-       rpc get-all-group-statistics {
-               input {
-            uses inv:node;
+    // RPC calls
+    rpc get-all-group-statistics {
+        input {
+            uses inv:node-context-ref;
         }
         output {
-               uses group-types:group-statistics-reply;
+            uses group-types:group-statistics-reply;
             uses tr:transaction-aware;
         }
-       
-       }
-       
-       rpc get-group-statistics {
-               input {
-            uses inv:node;
+    
+    }
+    
+    rpc get-group-statistics {
+        input {
+            uses inv:node-context-ref;
             leaf group-id{
-               type group-types:group-id;
+                type group-types:group-id;
             }
            
         }
@@ -63,56 +63,56 @@ module opendaylight-group-statistics {
             uses group-types:group-statistics-reply;
             uses tr:transaction-aware;
         }
-       
-       }
-       
-       rpc get-group-description {
-               input {
-            uses inv:node;
+    
+    }
+    
+    rpc get-group-description {
+        input {
+            uses inv:node-context-ref;
         }
         output {
             uses group-types:group-desc-stats-reply;
             uses tr:transaction-aware;
         }
-       }
-       
-       rpc get-group-features {
-               input {
-            uses inv:node;
+    }
+    
+    rpc get-group-features {
+        input {
+            uses inv:node-context-ref;
         }
         output {
             uses group-types:group-features-reply;
             uses tr:transaction-aware;
         }
-       }
-       
+    }
+    
 
-       //Notification calls
-       
-       notification group-statistics-updated {
-               leaf moreReplies {
-                       type boolean;
-               }
-               uses inv:node;
-               uses group-types:group-statistics-reply;
+    //Notification calls
+    
+    notification group-statistics-updated {
+        leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+        uses group-types:group-statistics-reply;
         uses tr:transaction-aware;
-       }
-       
-       notification group-desc-stats-updated {
-               leaf moreReplies {
-                       type boolean;
-               }
-               uses inv:node;
-               uses group-types:group-desc-stats-reply;
+    }
+    
+    notification group-desc-stats-updated {
+        leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+        uses group-types:group-desc-stats-reply;
         uses tr:transaction-aware;
-       }
+    }
 
-       notification group-features-updated {
-               leaf moreReplies {
-                       type boolean;
-               }
-               uses inv:node;
-               uses group-types:group-features-reply;
+    notification group-features-updated {
+        leaf moreReplies {
+            type boolean;
+        }
+        uses inv:node;
+        uses group-types:group-features-reply;
         uses tr:transaction-aware;
-       }
+    }
 }
index c22bdd3906bb801f1a2432329dff8ef9c9f40292..e3b2a3fc6477430d676e0542b5db91667a704ba5 100644 (file)
@@ -8,8 +8,8 @@ module opendaylight-meter-statistics {
     import flow-capable-transaction {prefix tr;}
     
     contact
-       "Anilkumar Vishnoi
-       Email: avishnoi@in.ibm.com";
+        "Anilkumar Vishnoi
+        Email: avishnoi@in.ibm.com";
 
     revision "2013-11-11" {
         description "Initial revision of meter statistics service";
@@ -18,103 +18,103 @@ module opendaylight-meter-statistics {
     augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-meter-statistics";
         container meter-statistics {
-               //config "false";
-               uses meter-types:meter-statistics-reply;
+            //config "false";
+            uses meter-types:meter-statistics-reply;
         }
     }
 
-       augment "/inv:nodes/inv:node" {
+    augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-meter-config-stats";
         container meter-config-stats {
-               //config "false";
-               uses meter-types:meter-config-stats-reply;
+            //config "false";
+            uses meter-types:meter-config-stats-reply;
         }
     }
-       
-       augment "/inv:nodes/inv:node" {
+    
+    augment "/inv:nodes/inv:node" {
         ext:augment-identifier "node-meter-features";
         container meter-features {
-               //config "false";
-               uses meter-types:meter-features-reply;
+            //config "false";
+            uses meter-types:meter-features-reply;
         }
     }
 
-       // RPC calls
-       rpc get-all-meter-statistics {
-               input {
-            uses inv:node;
+    // RPC calls
+    rpc get-all-meter-statistics {
+        input {
+            uses inv:node-context-ref;
         }
         output {
-                       uses meter-types:meter-statistics-reply;
-                       uses tr:transaction-aware;
+            uses meter-types:meter-statistics-reply;
+            uses tr:transaction-aware;
         }
-       
-       }
-       
-       rpc get-meter-statistics {
-               input {
-            uses inv:node;
+    
+    }
+    
+    rpc get-meter-statistics {
+        input {
+            uses inv:node-context-ref;
             leaf meter-id{
-               type meter-types:meter-id;
+                type meter-types:meter-id;
             }
         }
         output {
             uses meter-types:meter-statistics-reply;
             uses tr:transaction-aware;
         }
-       
-       }
-       
-       rpc get-all-meter-config-statistics {
-               input {
-            uses inv:node;
+    
+    }
+    
+    rpc get-all-meter-config-statistics {
+        input {
+            uses inv:node-context-ref;
         }
         output {
-               uses meter-types:meter-config-stats-reply;
+               uses meter-types:meter-config-stats-reply;
             uses tr:transaction-aware;
         }
-       }
-       
-       rpc get-meter-features {
-               input {
-            uses inv:node;
+    }
+    
+    rpc get-meter-features {
+        input {
+            uses inv:node-context-ref;
         }
         output {
-               uses meter-types:meter-features-reply;
+            uses meter-types:meter-features-reply;
             uses tr:transaction-aware;
         }
-       }
-       
+    }
+    
 
-       //Notification calls
-       
-       notification meter-statistics-updated {
-               leaf moreReplies {
-                       type boolean;
-               }
-               
-               uses inv:node;
+    //Notification calls
+    
+    notification meter-statistics-updated {
+        leaf moreReplies {
+            type boolean;
+        }
+        
+        uses inv:node;
         uses meter-types:meter-statistics-reply;
         uses tr:transaction-aware;
-       }
-       
-       notification meter-config-stats-updated {
-               leaf moreReplies {
-                       type boolean;
-               }
-           
+    }
+    
+    notification meter-config-stats-updated {
+        leaf moreReplies {
+            type boolean;
+        }
+        
         uses inv:node;
-           uses meter-types:meter-config-stats-reply;
-       uses tr:transaction-aware;
-       }
+        uses meter-types:meter-config-stats-reply;
+        uses tr:transaction-aware;
+    }
 
-       notification meter-features-updated {
-               leaf moreReplies {
-                       type boolean;
-               }
-               
-               uses inv:node;
+    notification meter-features-updated {
+        leaf moreReplies {
+            type boolean;
+        }
+        
+        uses inv:node;
         uses meter-types:meter-features-reply;
         uses tr:transaction-aware;
-       }
+    }
 }
index 34ad23844f363da800bc33a12b9dfee7eae045cb..2f3b7a036c6113b23d8020dd207c30ce490e6ab6 100644 (file)
@@ -40,6 +40,7 @@
                 <configuration>
                     <instructions>
                         <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                        <Import-Package>*,org.opendaylight.yangtools.yang.binding.annotations</Import-Package>
                     </instructions>
                 </configuration>
             </plugin>
index 801e4984c0401b04ce268b11fb2f5c9360f71f57..90fcbd99aaaad0a6f6448faf0428cbc46cc52b4d 100644 (file)
@@ -57,7 +57,14 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
         val targetCls = createClass(iface.directProxyName, supertype) [
             field(DELEGATE_FIELD, iface);
             implementMethodsFrom(supertype) [
-                body = '''return ($r) Â«DELEGATE_FIELD».«it.name»($$);'''
+                body = '''
+                {
+                    if(«DELEGATE_FIELD» == null) {
+                        throw new java.lang.IllegalStateException("No provider is processing supplied message");
+                    }
+                    return ($r) Â«DELEGATE_FIELD».«it.name»($$);
+                }
+                '''
             ]
         ]
         return targetCls.toClass(iface.classLoader).newInstance as T
index d60ad989627846d308dce74132877bd1ebdb6ccd..4ef9d80b02c2f34a34de5f7e6360857565bb71fe 100644 (file)
@@ -41,7 +41,7 @@ public class TestHelper {
                 mavenBundle("org.opendaylight.bgpcep", "framework").versionAsInProject(), //
                 mavenBundle("org.opendaylight.bgpcep", "util").versionAsInProject(), //
                 mavenBundle("commons-codec", "commons-codec").versionAsInProject(),
-                
+
                 mavenBundle(CONTROLLER, "config-api").versionAsInProject(), // //
                 mavenBundle(CONTROLLER, "config-manager").versionAsInProject(), // //
                 mavenBundle("commons-io", "commons-io").versionAsInProject(), //
@@ -53,30 +53,30 @@ public class TestHelper {
                 mavenBundle(CONTROLLER, "logback-config").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "config-persister-api").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-api").versionAsInProject(), //
-               
+
                 mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-util").versionAsInProject(), //
                 mavenBundle(CONTROLLER + ".thirdparty", "ganymed", "1.0-SNAPSHOT"), //
                 mavenBundle(CONTROLLER, "netconf-mapping-api").versionAsInProject(), //
 
                 mavenBundle(CONTROLLER, "config-persister-impl").versionAsInProject(), //
-                
+
                 mavenBundle("io.netty", "netty-handler").versionAsInProject(), //
                 mavenBundle("io.netty", "netty-codec").versionAsInProject(), //
                 mavenBundle("io.netty", "netty-buffer").versionAsInProject(), //
                 mavenBundle("io.netty", "netty-transport").versionAsInProject(), //
                 mavenBundle("io.netty", "netty-common").versionAsInProject(), //
-                
+
                 mavenBundle("org.opendaylight.controller.thirdparty", "exificient", "0.9.2-SNAPSHOT"), //
-                
+
                 mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.xerces", "2.11.0_1"),
                 mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"),
-                
+
                 mavenBundle(CONTROLLER, "config-netconf-connector").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-impl").versionAsInProject(), //
-                
+
                 mavenBundle(CONTROLLER, "config-persister-file-adapter").versionAsInProject().noStart());
-            
+
     }
 
     public static Option bindingAwareSalBundles() {
@@ -111,10 +111,12 @@ public class TestHelper {
 
                 systemProperty("netconf.tcp.address").value("0.0.0.0"), //
                 systemProperty("netconf.tcp.port").value("18383"), //
-                systemProperty("netconf.config.persister.storageAdapterClass").value(
+                systemProperty("netconf.config.persister.active").value("1"), //
+                systemProperty("netconf.config.persister.1.storageAdapterClass").value(
                         "org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter"), //
-                systemProperty("fileStorage").value(PathUtils.getBaseDir() + "/src/test/resources/controller.config"), //
-                systemProperty("numberOfBackups").value("1") //
+                systemProperty("netconf.config.persister.1.properties.fileStorage")
+                        .value(PathUtils.getBaseDir() + "/src/test/resources/controller.config"), //
+                systemProperty("netconf.config.persister.1.properties.numberOfBackups").value("1") //
                 //systemProperty("yangstore.blacklist").value(".*controller.model.*") //
 
         );
@@ -169,7 +171,7 @@ public class TestHelper {
                  * org/mockito/cglib/proxy/Factory have different Class objects
                  * for the type org/mockito/cglib/ proxy/Callback used in the
                  * signature
-                 * 
+                 *
                  * So we disable the bootdelegation. this property has no effect
                  * on the other OSGi implementation.
                  */
index 2a556c9be41c235aee2fb76ff8b712ffe33c6761..12759246140a9d7da0947ff8f73e8d461e6614d6 100644 (file)
@@ -17,6 +17,9 @@ import java.net.InetSocketAddress;
 import javax.net.ssl.SSLContext;
 
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
 import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
 import org.osgi.framework.BundleContext;
 
@@ -75,8 +78,13 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         EventLoopGroup bossGroup = getBossThreadGroupDependency();
         EventLoopGroup workerGroup = getWorkerThreadGroupDependency();
         Optional<SSLContext> maybeContext = Optional.absent();
-        NetconfClientDispatcher dispatcher = new NetconfClientDispatcher(maybeContext , bossGroup, workerGroup);
-        
+        NetconfClientDispatcher dispatcher = null;
+        if(getTcpOnly()) {
+            dispatcher = new NetconfClientDispatcher(maybeContext , bossGroup, workerGroup);
+        } else {
+            AuthenticationHandler authHandler = new LoginPassword(getUsername(),getPassword());
+            dispatcher = new NetconfSshClientDispatcher(authHandler , bossGroup, workerGroup);
+        }
         getDomRegistryDependency().registerProvider(device, bundleContext);
         
         device.start(dispatcher);
index 45f10162ca7edd600ca86bc5a56ac3cfb229fafb..923851411090a9c93f9b0cf1d59e9be1a197a92b 100644 (file)
@@ -45,7 +45,18 @@ module odl-sal-netconf-connector-cfg {
             leaf port {
                 type uint32;
             }
+            
+            leaf tcp-only {
+                type boolean;
+            }
 
+            leaf username {
+                type string;
+            }
+            
+            leaf password {
+                type string;
+            }
             container dom-registry {
                 uses config:service-ref {
                     refine type {
index 351ae6ebbee085614943d7608ec51669a204f1ff..36b46a171cde4706a1b7e22d17ed4c7e00ccdc90 100644 (file)
@@ -47,13 +47,27 @@ class JsonMapper {
         checkNotNull(parent);
         checkNotNull(parentSchema);
 
+        List<String> longestPathToElementViaChoiceCase = new ArrayList<>();
         for (Node<?> child : parent.getChildren()) {
-            DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
-            if (childSchema == null) {
-                throw new UnsupportedDataTypeException("Probably the data node \"" + child.getNodeType().getLocalName()
-                        + "\" is not conform to schema");
+            Deque<String> choiceCasePathStack = new ArrayDeque<>(longestPathToElementViaChoiceCase);
+            SchemaLocation schemaLocation = findFirstSchemaForNode(child, parentSchema.getChildNodes(),
+                    choiceCasePathStack);
+
+            if (schemaLocation == null) {
+                if (!choiceCasePathStack.isEmpty()) {
+                    throw new UnsupportedDataTypeException("On choice-case path " + choiceCasePathStack
+                            + " wasn't found data schema for " + child.getNodeType().getLocalName());
+                } else {
+                    throw new UnsupportedDataTypeException("Probably the data node \""
+                            + child.getNodeType().getLocalName() + "\" is not conform to schema");
+                }
             }
 
+            longestPathToElementViaChoiceCase = resolveLongerPath(longestPathToElementViaChoiceCase,
+                    schemaLocation.getLocation());
+
+            DataSchemaNode childSchema = schemaLocation.getSchema();
+
             if (childSchema instanceof ContainerSchemaNode) {
                 Preconditions.checkState(child instanceof CompositeNode,
                         "Data representation of Container should be CompositeNode - " + child.getNodeType());
@@ -83,7 +97,10 @@ class JsonMapper {
         }
 
         for (Node<?> child : parent.getChildren()) {
-            DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
+            SchemaLocation schemaLocation = findFirstSchemaForNode(child, parentSchema.getChildNodes(),
+                    new ArrayDeque<>(longestPathToElementViaChoiceCase));
+
+            DataSchemaNode childSchema = schemaLocation.getSchema();
             if (childSchema instanceof LeafListSchemaNode) {
                 foundLeafLists.remove((LeafListSchemaNode) childSchema);
             } else if (childSchema instanceof ListSchemaNode) {
@@ -92,10 +109,45 @@ class JsonMapper {
         }
     }
 
-    private DataSchemaNode findFirstSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode) {
+    private List<String> resolveLongerPath(List<String> l1, List<String> l2) {
+        return l1.size() > l2.size() ? l1 : l2;
+    }
+
+    private SchemaLocation findFirstSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode,
+            Deque<String> pathIterator) {
+        Map<String, ChoiceNode> choiceSubnodes = new HashMap<>();
         for (DataSchemaNode dsn : dataSchemaNode) {
-            if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
-                return dsn;
+            if (dsn instanceof ChoiceNode) {
+                choiceSubnodes.put(dsn.getQName().getLocalName(), (ChoiceNode) dsn);
+            } else if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
+                return new SchemaLocation(dsn);
+            }
+        }
+
+        for (ChoiceNode choiceSubnode : choiceSubnodes.values()) {
+            if ((!pathIterator.isEmpty() && pathIterator.peekLast().equals(choiceSubnode.getQName().getLocalName()))
+                    || pathIterator.isEmpty()) {
+                String pathPartChoice = pathIterator.pollLast();
+                for (ChoiceCaseNode concreteCase : choiceSubnode.getCases()) {
+                    if ((!pathIterator.isEmpty() && pathIterator.peekLast().equals(
+                            concreteCase.getQName().getLocalName()))
+                            || pathIterator.isEmpty()) {
+                        String pathPartCase = pathIterator.pollLast();
+                        SchemaLocation schemaLocation = findFirstSchemaForNode(node, concreteCase.getChildNodes(),
+                                pathIterator);
+                        if (schemaLocation != null) {
+                            schemaLocation.addPathPart(concreteCase.getQName().getLocalName());
+                            schemaLocation.addPathPart(choiceSubnode.getQName().getLocalName());
+                            return schemaLocation;
+                        }
+                        if (pathPartCase != null) {
+                            pathIterator.addLast(pathPartCase);
+                        }
+                    }
+                }
+                if (pathPartChoice != null) {
+                    pathIterator.addLast(pathPartChoice);
+                }
             }
         }
         return null;
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/SchemaLocation.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/SchemaLocation.java
new file mode 100644 (file)
index 0000000..24055ce
--- /dev/null
@@ -0,0 +1,28 @@
+package org.opendaylight.controller.sal.rest.impl;
+
+import java.util.*;
+
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class SchemaLocation {
+    final private List<String> location = new ArrayList<>();
+    final private DataSchemaNode schema;
+
+    public SchemaLocation(DataSchemaNode schema) {
+        this.schema = schema;
+    }
+
+    DataSchemaNode getSchema() {
+        return schema;
+    }
+
+    List<String> getLocation() {
+        return location;
+    }
+
+    SchemaLocation addPathPart(String partOfPath) {
+        location.add(partOfPath);
+        return this;
+    }
+
+}
index bc941b997e35dd63c8a3250cb52e8ccf66e27314..89d24ad0579b9b78a77a68f121d8f13ca75ef399 100644 (file)
@@ -137,16 +137,22 @@ final class TestUtils {
 
     static String convertCompositeNodeDataAndYangToJson(CompositeNode compositeNode, String yangPath,
             String outputPath, String searchedModuleName, String searchedDataSchemaName) {
-        String jsonResult = null;
-        Set<Module> modules = null;
+        Set<Module> modules = resolveModules(yangPath);
+        Module module = resolveModule(searchedModuleName, modules);
+        DataSchemaNode dataSchemaNode = resolveDataSchemaNode(module, searchedDataSchemaName);
 
         try {
-            modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangPath).getPath());
-        } catch (FileNotFoundException e) {
+            return writeCompNodeWithSchemaContextToJson(compositeNode, outputPath, modules, dataSchemaNode);
+        } catch (WebApplicationException | IOException e) {
+            // TODO Auto-generated catch block
             e.printStackTrace();
         }
-        assertNotNull("modules can't be null.", modules);
+        return null;
 
+    }
+
+    static Module resolveModule(String searchedModuleName, Set<Module> modules) {
+        assertNotNull("modules can't be null.", modules);
         Module module = null;
         if (searchedModuleName != null) {
             for (Module m : modules) {
@@ -158,12 +164,24 @@ final class TestUtils {
         } else if (modules.size() == 1) {
             module = modules.iterator().next();
         }
-        assertNotNull("Module is missing", module);
+        return module;
+    }
 
-        assertNotNull("Composite node can't be null", compositeNode);
+    static Set<Module> resolveModules(String yangPath) {
+        Set<Module> modules = null;
+
+        try {
+            modules = TestUtils.loadModules(ToJsonBasicDataTypesTest.class.getResource(yangPath).getPath());
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+
+        return modules;
+    }
+
+    static DataSchemaNode resolveDataSchemaNode(Module module, String searchedDataSchemaName) {
+        assertNotNull("Module is missing", module);
 
-        StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE;
-        ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
         DataSchemaNode dataSchemaNode = null;
         if (searchedDataSchemaName != null) {
             for (DataSchemaNode dsn : module.getChildNodes()) {
@@ -174,19 +192,23 @@ final class TestUtils {
         } else if (module.getChildNodes().size() == 1) {
             dataSchemaNode = module.getChildNodes().iterator().next();
         }
+        return dataSchemaNode;
+    }
+
+    static String writeCompNodeWithSchemaContextToJson(CompositeNode compositeNode, String outputPath,
+            Set<Module> modules, DataSchemaNode dataSchemaNode) throws IOException, WebApplicationException {
+        String jsonResult;
+
         assertNotNull(dataSchemaNode);
-        // SchemaContextUtil.
+        assertNotNull("Composite node can't be null", compositeNode);
+        ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
 
-        ControllerContext controllerContext = ControllerContext.getInstance();
-        controllerContext.setSchemas(loadSchemaContext(modules));
-        StructuredData structuredData = new StructuredData(compositeNode, dataSchemaNode);
-        try {
-            structuredDataToJsonProvider.writeTo(structuredData, null, null, null, null, null, byteArrayOS);
-        } catch (WebApplicationException | IOException e) {
-            e.printStackTrace();
-        }
-        assertFalse("Returning JSON string can't be empty for node " + dataSchemaNode.getQName().getLocalName(),
-                byteArrayOS.toString().isEmpty());
+        ControllerContext contContext = ControllerContext.getInstance();
+        contContext.setSchemas(loadSchemaContext(modules));
+        
+        StructuredDataToJsonProvider structuredDataToJsonProvider = StructuredDataToJsonProvider.INSTANCE;
+        structuredDataToJsonProvider.writeTo(new StructuredData(compositeNode, dataSchemaNode), null, null, null, null,
+                null, byteArrayOS);
 
         jsonResult = byteArrayOS.toString();
         try {
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonChoiceCaseTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ToJsonChoiceCaseTest.java
new file mode 100644 (file)
index 0000000..141ffdb
--- /dev/null
@@ -0,0 +1,131 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.ws.rs.WebApplicationException;
+
+import org.junit.*;
+import org.opendaylight.yangtools.yang.model.api.*;
+
+public class ToJsonChoiceCaseTest {
+
+    private static Set<Module> modules;
+    private static DataSchemaNode dataSchemaNode;
+
+    @BeforeClass
+    public static void initialization() {
+        modules = TestUtils.resolveModules("/yang-to-json-conversion/choice");
+        Module module = TestUtils.resolveModule(null, modules);
+        dataSchemaNode = TestUtils.resolveDataSchemaNode(module, null);
+
+    }
+
+    /**
+     * Test when some data are in one case node and other in another. Exception
+     * expected!!
+     */
+    @Test
+    public void compNodeDataOnVariousChoiceCasePathTest() {
+        boolean exceptionCatched = false;
+        try {
+            TestUtils.writeCompNodeWithSchemaContextToJson(
+                    TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_various_path.xml"),
+                    "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+        } catch (UnsupportedDataTypeException e) {
+            exceptionCatched = true;
+
+        } catch (WebApplicationException | IOException e) {
+            // shouldn't end here
+            assertTrue(false);
+        }
+
+        assertTrue(exceptionCatched);
+
+    }
+
+    /**
+     * Test when second level data are red first, then first and at the end
+     * third level. Level represents pass through couple choice-case
+     */
+    @Ignore
+    @Test
+    public void compNodeDataWithRandomOrderAccordingLevel() {
+        try {
+            String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+                    TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_random_level.xml"),
+                    "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+        } catch (WebApplicationException | IOException e) {
+            // shouldn't end here
+            assertTrue(false);
+        }
+    }
+
+    /**
+     * Test when element from no first case is used
+     */
+    @Ignore
+    @Test
+    public void compNodeDataNoFirstCase() {
+        try {
+            String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+                    TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_no_first_case.xml"),
+                    "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+        } catch (WebApplicationException | IOException e) {
+            // shouldn't end here
+            assertTrue(false);
+        }
+    }
+
+    /**
+     * Test when element in case is list
+     */
+    @Ignore
+    @Test
+    public void compNodeDataAsList() {
+        try {
+            String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+                    TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_list.xml"),
+                    "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+        } catch (WebApplicationException | IOException e) {
+            // shouldn't end here
+            assertTrue(false);
+        }
+    }
+
+    /**
+     * Test when element in case is container
+     */
+    @Ignore
+    @Test
+    public void compNodeDataAsContainer() {
+        try {
+            String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+                    TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_container.xml"),
+                    "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+        } catch (WebApplicationException | IOException e) {
+            // shouldn't end here
+            assertTrue(false);
+        }
+    }
+
+    /**
+     * Test when element in case is container
+     */
+    @Ignore
+    @Test
+    public void compNodeDataAsLeafList() {
+        try {
+            String jsonOutput = TestUtils.writeCompNodeWithSchemaContextToJson(
+                    TestUtils.loadCompositeNode("/yang-to-json-conversion/choice/xml/data_leaflist.xml"),
+                    "/yang-to-json-conversion/choice/xml", modules, dataSchemaNode);
+        } catch (WebApplicationException | IOException e) {
+            // shouldn't end here
+            assertTrue(false);
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/choice.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/choice.yang
new file mode 100644 (file)
index 0000000..8b02a92
--- /dev/null
@@ -0,0 +1,97 @@
+module choice-case-test {
+       namespace "choice:case:test";  
+       
+       prefix "chcatst";
+       revision 2013-11-27 {    
+       }
+       
+       container cont {
+               leaf lf1 {
+                       type string;
+               }               
+               
+               choice choi1 {
+                       case a1 {
+                               leaf lf1a {
+                                       type uint16;    
+                               }
+                               choice choi1a {
+                                       case aa1 {
+                                               leaf lf1aa {
+                                                       type string;
+                                               }
+                                               choice choi1aa {
+                                                       case aaa1 {
+                                                               leaf lf1aaa {
+                                                                       type string;
+                                                               }
+                                                       }
+                                                       case aab1 {
+                                                               leaf lf1aab {
+                                                                       type string;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       case ab1 {
+                                               leaf lf1ab {
+                                                       type string;
+                                               }
+                                       }
+                               }
+                       }                       
+                       case b1 {
+                               list lst1b {
+                                       leaf lf11b {
+                                               type string;
+                                       }
+                               }
+                       }
+                       case c1 {
+                               container cont1c {
+                                       leaf lf11c {
+                                               type string;
+                                       }
+                               }
+                       }
+                       case d1 {
+                               leaf-list lflst1d {
+                                       type string;
+                               }
+                       }
+               }
+               
+               choice choi2 {
+                       case a2 {
+                               leaf lf2a {
+                                       type string;
+                               }
+                       }
+                       case b2 {
+                               leaf lf2b {
+                                       type string;
+                               }
+                       }
+               }
+               
+/*              equal identifiers in various cases are illegal 7.9.2 rfc6020 */
+/*             
+               choice choi3 {
+                       case 3a {
+                               leaf lf3a {
+                                       type string;
+                               }
+                       }
+                       case 3b {
+                               leaf lf3b {
+                                       type string;
+                               }
+                       }
+               }
+*/
+                               
+       }
+  
+       
+
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_container.xml
new file mode 100644 (file)
index 0000000..9c75194
--- /dev/null
@@ -0,0 +1,5 @@
+<cont>
+       <cont1c>
+               <lf11c>lf11c val</lf11c>
+       </cont1c>
+</cont>
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_leaflist.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_leaflist.xml
new file mode 100644 (file)
index 0000000..6cebb64
--- /dev/null
@@ -0,0 +1,4 @@
+<cont>
+       <lflst1d>lflst1d_1 val</lflst1d>
+       <lflst1d>lflst1d_2 val</lflst1d>
+</cont>
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_list.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_list.xml
new file mode 100644 (file)
index 0000000..710da55
--- /dev/null
@@ -0,0 +1,8 @@
+<cont>
+       <lst1b>
+               <lf11b>lf11b_1 val</lf11b>
+       </lst1b>
+       <lst1b>
+               <lf11b>lf11b_2 val</lf11b>
+       </lst1b>
+</cont>
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_more_choices_same_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_more_choices_same_level.xml
new file mode 100644 (file)
index 0000000..9c75194
--- /dev/null
@@ -0,0 +1,5 @@
+<cont>
+       <cont1c>
+               <lf11c>lf11c val</lf11c>
+       </cont1c>
+</cont>
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_no_first_case.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_no_first_case.xml
new file mode 100644 (file)
index 0000000..43e9974
--- /dev/null
@@ -0,0 +1,5 @@
+<cont>
+       <lf1>lf1 val</lf1>
+       <lf1a>121</lf1a>
+       <lf1ab>lf1ab val</lf1ab>
+</cont>
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_random_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_random_level.xml
new file mode 100644 (file)
index 0000000..b1b78e4
--- /dev/null
@@ -0,0 +1,6 @@
+<cont>
+       <lf1aa>lf1aa val</lf1aa>
+       <lf1>lf1 val</lf1>
+       <lf1a>121</lf1a>
+       <lf1aaa>lf1aaa val</lf1aaa>
+</cont>
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_various_path.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/yang-to-json-conversion/choice/xml/data_various_path.xml
new file mode 100644 (file)
index 0000000..c43dab6
--- /dev/null
@@ -0,0 +1,6 @@
+<cont>
+       <lf1aa>lf1aa val</lf1aa>
+       <lf1>lf1 val</lf1>
+       <lf1a>121</lf1a>
+       <lf1ab>lf1ab value</lf1ab>      
+</cont>
\ No newline at end of file
index d1ab3515035dfb0b5597c263c5f23ac29656d659..cdcd1ef32edde93dbc83745a62c97f81a2f42a83 100644 (file)
@@ -24,6 +24,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupFeaturesOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
@@ -112,7 +113,7 @@ public class StatisticsProvider implements AutoCloseable {
         
         spLogger.debug("Statistics requester thread started with timer interval : {}",5000);
         
-        statisticsRequesterThread.start();
+        //statisticsRequesterThread.start();
         
         spLogger.info("Statistics Provider started.");
     }
@@ -137,76 +138,86 @@ public class StatisticsProvider implements AutoCloseable {
             //We need to add check, so see if groups/meters are supported
             //by the target node. Below check doesn't look good.
             if(targetNode.getId().getValue().contains("openflow:")){
-                sendAllGroupStatisticsRequest(targetNode);
+                InstanceIdentifier<Node> targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance();
+                NodeRef targetNodeRef = new NodeRef(targetInstanceId);
                 
-                sendAllMeterStatisticsRequest(targetNode);
+                sendAllGroupStatisticsRequest(targetNodeRef);
                 
-                sendGroupDescriptionRequest(targetNode);
+                sendAllMeterStatisticsRequest(targetNodeRef);
                 
-                sendGroupFeaturesRequest(targetNode);
+                sendGroupDescriptionRequest(targetNodeRef);
                 
-                sendMeterConfigStatisticsRequest(targetNode);
+                sendGroupFeaturesRequest(targetNodeRef);
                 
-                sendMeterFeaturesRequest(targetNode);
+                sendMeterConfigStatisticsRequest(targetNodeRef);
+                
+                sendMeterFeaturesRequest(targetNodeRef);
             }
         }
     }
     
-    private void sendAllGroupStatisticsRequest(Node targetNode){
+    private void sendAllGroupStatisticsRequest(NodeRef targetNode){
         
         final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
         
-        input.setId(targetNode.getId());
+        input.setNode(targetNode);
+        input.setNode(targetNode);
 
+        @SuppressWarnings("unused")
         Future<RpcResult<GetAllGroupStatisticsOutput>> response = 
                 groupStatsService.getAllGroupStatistics(input.build());
     }
     
-    private void sendGroupDescriptionRequest(Node targetNode){
+    private void sendGroupDescriptionRequest(NodeRef targetNode){
         final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
         
-        input.setId(targetNode.getId());
-        
+        input.setNode(targetNode);
+
+        @SuppressWarnings("unused")
         Future<RpcResult<GetGroupDescriptionOutput>> response = 
                 groupStatsService.getGroupDescription(input.build());
     }
     
-    private void sendGroupFeaturesRequest(Node targetNode){
+    private void sendGroupFeaturesRequest(NodeRef targetNode){
         
         GetGroupFeaturesInputBuilder input = new GetGroupFeaturesInputBuilder();
         
-        input.setId(targetNode.getId());
-        
+        input.setNode(targetNode);
+
+        @SuppressWarnings("unused")
         Future<RpcResult<GetGroupFeaturesOutput>> response = 
                 groupStatsService.getGroupFeatures(input.build());
     }
     
-    private void sendAllMeterStatisticsRequest(Node targetNode){
+    private void sendAllMeterStatisticsRequest(NodeRef targetNode){
         
         GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
         
-        input.setId(targetNode.getId());
-        
+        input.setNode(targetNode);
+
+        @SuppressWarnings("unused")
         Future<RpcResult<GetAllMeterStatisticsOutput>> response = 
                 meterStatsService.getAllMeterStatistics(input.build());
     }
     
-    private void sendMeterConfigStatisticsRequest(Node targetNode){
+    private void sendMeterConfigStatisticsRequest(NodeRef targetNode){
         
         GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
         
-        input.setId(targetNode.getId());
-        
+        input.setNode(targetNode);
+
+        @SuppressWarnings("unused")
         Future<RpcResult<GetAllMeterConfigStatisticsOutput>> response = 
                 meterStatsService.getAllMeterConfigStatistics(input.build());
         
     }
-    private void sendMeterFeaturesRequest(Node targetNode){
+    private void sendMeterFeaturesRequest(NodeRef targetNode){
      
         GetMeterFeaturesInputBuilder input = new GetMeterFeaturesInputBuilder();
         
-        input.setId(targetNode.getId());
-        
+        input.setNode(targetNode);
+
+        @SuppressWarnings("unused")
         Future<RpcResult<GetMeterFeaturesOutput>> response = 
                 meterStatsService.getMeterFeatures(input.build());
     }
@@ -241,7 +252,6 @@ public class StatisticsProvider implements AutoCloseable {
           } catch (Throwable e) {
             throw Exceptions.sneakyThrow(e);
           }
-
     }
 
 }
index 1ef2ae375e723f3fb49e4890c3b0a1f1022e8d44..4b6dcfd46528b3068fe2a7c41dc9b9224f205b9c 100644 (file)
@@ -14,28 +14,70 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribu
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
 public abstract class AttributeIfcSwitchStatement<T> {
 
+    protected AttributeIfc lastAttribute;
+
     public T switchAttribute(AttributeIfc attributeIfc) {
 
+        this.lastAttribute = attributeIfc;
+
         if (attributeIfc instanceof JavaAttribute) {
-            return caseJavaAttribute((JavaAttribute) attributeIfc);
+            try {
+                return caseJavaAttribute(attributeIfc.getOpenType());
+            } catch (UnknownOpenTypeException e) {
+                throw getIllegalArgumentException(attributeIfc);
+            }
+
         } else if (attributeIfc instanceof DependencyAttribute) {
-            return caseDependencyAttribute((DependencyAttribute) attributeIfc);
+            return caseDependencyAttribute(((DependencyAttribute) attributeIfc).getOpenType());
         } else if (attributeIfc instanceof ListAttribute) {
-            return caseListAttribute((ListAttribute) attributeIfc);
+            return caseListAttribute(((ListAttribute) attributeIfc).getOpenType());
         } else if (attributeIfc instanceof TOAttribute) {
-            return caseTOAttribute((TOAttribute) attributeIfc);
+            return caseTOAttribute(((TOAttribute) attributeIfc).getOpenType());
+        }
+
+        throw getIllegalArgumentException(attributeIfc);
+    }
+
+    private IllegalArgumentException getIllegalArgumentException(AttributeIfc attributeIfc) {
+        return new IllegalArgumentException("Unknown attribute type " + attributeIfc.getClass() + ", " + attributeIfc
+                + " with open type:" + attributeIfc.getOpenType());
+    }
+
+    public final T caseJavaAttribute(OpenType<?> openType) {
+        if (openType instanceof SimpleType<?>) {
+            return caseJavaSimpleAttribute((SimpleType<?>) openType);
+        } else if (openType instanceof ArrayType<?>) {
+            return caseJavaArrayAttribute((ArrayType<?>) openType);
+        } else if (openType instanceof CompositeType) {
+            return caseJavaCompositeAttribute((CompositeType) openType);
         }
 
-        throw new IllegalArgumentException("Unknown attribute type " + attributeIfc.getClass() + ", " + attributeIfc);
+        throw new UnknownOpenTypeException("Unknown attribute open type " + openType);
     }
 
-    protected abstract T caseJavaAttribute(JavaAttribute attributeIfc);
+    protected abstract T caseJavaSimpleAttribute(SimpleType<?> openType);
+
+    protected abstract T caseJavaArrayAttribute(ArrayType<?> openType);
+
+    protected abstract T caseJavaCompositeAttribute(CompositeType openType);
 
-    protected abstract T caseDependencyAttribute(DependencyAttribute attributeIfc);
+    protected abstract T caseDependencyAttribute(SimpleType<?> attributeIfc);
 
-    protected abstract T caseTOAttribute(TOAttribute attributeIfc);
+    protected abstract T caseTOAttribute(CompositeType openType);
 
-    protected abstract T caseListAttribute(ListAttribute attributeIfc);
+    protected abstract T caseListAttribute(ArrayType<?> openType);
+
+
+    private static class UnknownOpenTypeException extends RuntimeException {
+        public UnknownOpenTypeException(String message) {
+            super(message);
+        }
+    }
 }
index 2ba1b61b80d5a76d3856d76d71cb910746dae462..867d94e0b70f628a1454cde825f44d6c27233528 100644 (file)
@@ -8,27 +8,26 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
-import java.util.List;
-
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 
-public abstract class AbstractAttributeReadingStrategy<A extends AttributeIfc> implements AttributeReadingStrategy {
+import java.util.List;
+
+public abstract class AbstractAttributeReadingStrategy implements AttributeReadingStrategy {
 
-    private final A attributeIfc;
+    private final String nullableDefault;
 
-    public AbstractAttributeReadingStrategy(A attributeIfc) {
-        this.attributeIfc = attributeIfc;
+    public AbstractAttributeReadingStrategy(String nullableDefault) {
+        this.nullableDefault = nullableDefault;
     }
 
-    public A getAttributeIfc() {
-        return attributeIfc;
+    public String getNullableDefault() {
+        return nullableDefault;
     }
 
     @Override
     public AttributeConfigElement readElement(List<XmlElement> configNodes) {
         if (configNodes.size() == 0)
-            return AttributeConfigElement.createNullValue(attributeIfc);
+            return AttributeConfigElement.createNullValue(nullableDefault);
 
         return readElementHook(configNodes);
     }
index f07e74035c0c539bd649a4e0095490cdb857c7e8..8f569619001c0d8c60697a92d160e730740ba567 100644 (file)
@@ -9,12 +9,11 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
 import com.google.common.collect.Lists;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 
 import java.util.List;
 
-public class ArrayAttributeReadingStrategy extends AbstractAttributeReadingStrategy<AttributeIfc> {
+public class ArrayAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
 
     private final AttributeReadingStrategy innerStrategy;
 
@@ -22,8 +21,8 @@ public class ArrayAttributeReadingStrategy extends AbstractAttributeReadingStrat
      * @param attributeIfc
      * @param innerStrategy
      */
-    public ArrayAttributeReadingStrategy(AttributeIfc attributeIfc, AttributeReadingStrategy innerStrategy) {
-        super(attributeIfc);
+    public ArrayAttributeReadingStrategy(String nullableDefault, AttributeReadingStrategy innerStrategy) {
+        super(nullableDefault);
         this.innerStrategy = innerStrategy;
     }
 
@@ -33,7 +32,7 @@ public class ArrayAttributeReadingStrategy extends AbstractAttributeReadingStrat
         for (int i = 0; i < configNodes.size(); i++) {
             innerList.add(innerStrategy.readElement(Lists.newArrayList(configNodes.get(i))).getValue());
         }
-        return AttributeConfigElement.create(getAttributeIfc(), innerList);
+        return AttributeConfigElement.create(getNullableDefault(), innerList);
     }
 
 }
index fa249da7f2c81d98d27d2940c17c314bec8dc55e..598935a0bc4f15ddcc61039723e313d55c0d9860 100644 (file)
@@ -8,12 +8,11 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
-import javax.management.openmbean.OpenType;
-
+import com.google.common.base.Optional;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
 
-import com.google.common.base.Optional;
+import javax.management.openmbean.OpenType;
 
 /**
  * Parsed xml element containing configuration for one attribute of an instance
@@ -49,13 +48,23 @@ public class AttributeConfigElement {
     }
 
     public static AttributeConfigElement create(AttributeIfc attributeIfc, Object value) {
-        return new AttributeConfigElement(attributeIfc.getNullableDefault(), value);
+        String nullableDefault = attributeIfc.getNullableDefault();
+        return create(nullableDefault, value);
+    }
+
+    public static AttributeConfigElement create(String nullableDefault, Object value) {
+        return new AttributeConfigElement(nullableDefault, value);
     }
 
     public static AttributeConfigElement createNullValue(AttributeIfc attributeIfc) {
         return new AttributeConfigElement(attributeIfc.getNullableDefault(), null);
     }
 
+    public static AttributeConfigElement createNullValue(String nullableDefault) {
+        return new AttributeConfigElement(nullableDefault, null);
+    }
+
+
     public Object getValue() {
         return value;
     }
index 1cfb74d652133eb2ad22db17f15ce2547a5a93c0..fdbfb98e1ca7e9f57c6421eda42f0c3bbd2d93c7 100644 (file)
@@ -11,21 +11,19 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-public class CompositeAttributeReadingStrategy extends AbstractAttributeReadingStrategy<TOAttribute> {
+public class CompositeAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
 
     private final Map<String, AttributeReadingStrategy> innerStrategies;
 
-    public CompositeAttributeReadingStrategy(TOAttribute attributeIfc,
+    public CompositeAttributeReadingStrategy(String nullableDefault,
             Map<String, AttributeReadingStrategy> innerStrategies) {
-        super(attributeIfc);
+        super(nullableDefault);
         this.innerStrategies = innerStrategies;
     }
 
@@ -38,21 +36,19 @@ public class CompositeAttributeReadingStrategy extends AbstractAttributeReadingS
 
         Map<String, Object> innerMap = Maps.newHashMap();
 
-        Map<String, AttributeIfc> inner = getAttributeIfc().getYangPropertiesToTypesMap();
-
         List<XmlElement> recognisedChildren = Lists.newArrayList();
-        for (Entry<String, AttributeIfc> innerAttrEntry : inner.entrySet()) {
+        for (Entry<String, AttributeReadingStrategy> innerAttrEntry : innerStrategies.entrySet()) {
             List<XmlElement> childItem = complexElement.getChildElementsWithSameNamespace(innerAttrEntry.getKey());
             recognisedChildren.addAll(childItem);
 
-            AttributeConfigElement resolvedInner = innerStrategies.get(innerAttrEntry.getKey()).readElement(childItem);
+            AttributeConfigElement resolvedInner = innerAttrEntry.getValue().readElement(childItem);
 
             innerMap.put(innerAttrEntry.getKey(), resolvedInner.getValue());
         }
 
         complexElement.checkUnrecognisedElements(recognisedChildren);
 
-        return AttributeConfigElement.create(getAttributeIfc(), innerMap);
+        return AttributeConfigElement.create(getNullableDefault(), innerMap);
     }
 
 }
index 59dc11f0b81fc78b2ee6405a5d323541cc04e1d3..7a4ba31255ac08e0099dab72830fe7cdbb2a48a3 100644 (file)
@@ -8,8 +8,6 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
 import com.google.common.base.Preconditions;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
@@ -17,12 +15,12 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import java.util.List;
 import java.util.Map;
 
-public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReadingStrategy<AttributeIfc> {
+public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
 
     private static final Object PREFIX_SEPARATOR = ":";
 
-    public ObjectNameAttributeReadingStrategy(DependencyAttribute attributeIfc) {
-        super(attributeIfc);
+    public ObjectNameAttributeReadingStrategy(String nullableDefault) {
+        super(nullableDefault);
     }
 
     @Override
@@ -33,7 +31,7 @@ public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReading
                 + " but was " + configNodes.size());
 
         Preconditions.checkNotNull(firstChild, "Element %s should be present", firstChild);
-        return AttributeConfigElement.create(getAttributeIfc(), resolve(firstChild));
+        return AttributeConfigElement.create(getNullableDefault(), resolve(firstChild));
     }
 
     private ObjectNameAttributeMappingStrategy.MappedDependency resolve(XmlElement firstChild) {
index 80a255507460d6d4b2d19369e8e9c2e56aefcdc8..bc3c74a88f218aa01ad82a97976ee704df8d1f86 100644 (file)
@@ -8,15 +8,15 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
+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.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 
 import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.SimpleType;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -41,26 +41,33 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadin
     }
 
     @Override
-    protected AttributeReadingStrategy caseJavaAttribute(JavaAttribute attributeIfc) {
-        if (attributeIfc.getOpenType() instanceof SimpleType<?>)
-            return new SimpleAttributeReadingStrategy(attributeIfc);
-        else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
-            SimpleAttributeReadingStrategy innerStrategy = new SimpleAttributeReadingStrategy(
-                    ((ArrayType<?>) attributeIfc.getOpenType()).getElementOpenType());
-            return new ArrayAttributeReadingStrategy(attributeIfc, innerStrategy);
-        }
-        throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
-                + " or " + ArrayType.class);
+    public AttributeReadingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
+        return new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault());
+    }
+
+    @Override
+    public AttributeReadingStrategy caseJavaArrayAttribute(ArrayType<?> openType) {
+        SimpleAttributeReadingStrategy innerStrategy = new SimpleAttributeReadingStrategy(lastAttribute.getNullableDefault());
+        return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
     }
 
     @Override
-    protected AttributeReadingStrategy caseDependencyAttribute(DependencyAttribute attributeIfc) {
-        return new ObjectNameAttributeReadingStrategy(attributeIfc);
+    public AttributeReadingStrategy caseJavaCompositeAttribute(CompositeType openType) {
+        Preconditions.checkState(openType.keySet().size() == 1, "Unexpected number of elements for open type %s, should be 1", openType);
+        String mappingKey = openType.keySet().iterator().next();
+        return new SimpleCompositeAttributeReadingStrategy(lastAttribute.getNullableDefault(), mappingKey);
     }
 
     @Override
-    protected AttributeReadingStrategy caseTOAttribute(TOAttribute attributeIfc) {
-        Map<String, AttributeIfc> inner = attributeIfc.getYangPropertiesToTypesMap();
+    protected AttributeReadingStrategy caseDependencyAttribute(SimpleType<?> openType) {
+        return new ObjectNameAttributeReadingStrategy(lastAttribute.getNullableDefault());
+    }
+
+    @Override
+    protected AttributeReadingStrategy caseTOAttribute(CompositeType openType) {
+        Preconditions.checkState(lastAttribute instanceof TOAttribute);
+        Map<String, AttributeIfc> inner = ((TOAttribute)lastAttribute).getYangPropertiesToTypesMap();
+
         Map<String, AttributeReadingStrategy> innerStrategies = Maps.newHashMap();
 
         for (Entry<String, AttributeIfc> innerAttrEntry : inner.entrySet()) {
@@ -69,14 +76,14 @@ public class ObjectXmlReader extends AttributeIfcSwitchStatement<AttributeReadin
             innerStrategies.put(innerAttrEntry.getKey(), innerStrat);
         }
 
-        return new CompositeAttributeReadingStrategy(attributeIfc, innerStrategies);
+        return new CompositeAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategies);
     }
 
     @Override
-    protected AttributeReadingStrategy caseListAttribute(ListAttribute attributeIfc) {
-        AttributeIfc innerAttr = attributeIfc.getInnerAttribute();
-        AttributeReadingStrategy innerStrategy = prepareReadingStrategy(key, innerAttr);
-        return new ArrayAttributeReadingStrategy(attributeIfc, innerStrategy);
+    protected AttributeReadingStrategy caseListAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListAttribute);
+        AttributeReadingStrategy innerStrategy = prepareReadingStrategy(key, ((ListAttribute) lastAttribute).getInnerAttribute());
+        return new ArrayAttributeReadingStrategy(lastAttribute.getNullableDefault(), innerStrategy);
     }
 
 }
index c5c287ffe2acf7561864dc5044d59eaaebce7bfe..be86a2ab6f58181894700e95e1f5bee413bc8a21 100644 (file)
@@ -9,23 +9,14 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
 
 import com.google.common.base.Preconditions;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 
-import javax.management.openmbean.OpenType;
 import java.util.List;
 
-public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStrategy<AttributeIfc> {
+public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
 
-    public SimpleAttributeReadingStrategy(AttributeIfc attributeIfc) {
-        super(attributeIfc);
-    }
-
-    /**
-     * @param elementOpenType
-     */
-    public SimpleAttributeReadingStrategy(OpenType<?> elementOpenType) {
-        super(new AttributeIfcWrapper(elementOpenType));
+    public SimpleAttributeReadingStrategy(String nullableDefault) {
+        super(nullableDefault);
     }
 
     @Override
@@ -37,50 +28,11 @@ public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStra
         String textContent = xmlElement.getTextContent();
 
         Preconditions.checkNotNull(textContent, "This element should contain text %s", xmlElement);
-        return AttributeConfigElement.create(getAttributeIfc(), textContent);
+        return AttributeConfigElement.create(getNullableDefault(), postprocessParsedValue(textContent));
     }
 
-    /**
-     * Wrapper for JavaAttribute inner element attributes (in case JavaAttribute
-     * is array)
-     */
-    static class AttributeIfcWrapper implements AttributeIfc {
-
-        private final OpenType<?> elementOpenType;
-
-        public AttributeIfcWrapper(OpenType<?> elementOpenType) {
-            this.elementOpenType = elementOpenType;
-        }
-
-        @Override
-        public String getAttributeYangName() {
-            return null;
-        }
-
-        @Override
-        public String getNullableDescription() {
-            return null;
-        }
-
-        @Override
-        public String getNullableDefault() {
-            return null;
-        }
-
-        @Override
-        public String getUpperCaseCammelCase() {
-            return null;
-        }
-
-        @Override
-        public String getLowerCaseCammelCase() {
-            return null;
-        }
-
-        @Override
-        public OpenType<?> getOpenType() {
-            return elementOpenType;
-        }
-
+    protected Object postprocessParsedValue(String textContent) {
+        return textContent;
     }
+
 }
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleCompositeAttributeReadingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleCompositeAttributeReadingStrategy.java
new file mode 100644 (file)
index 0000000..9249ac9
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.confignetconfconnector.mapping.attributes.fromxml;
+
+import com.google.common.collect.Maps;
+
+import java.util.HashMap;
+
+public class SimpleCompositeAttributeReadingStrategy extends SimpleAttributeReadingStrategy {
+
+
+    private final String key;
+
+    public SimpleCompositeAttributeReadingStrategy(String nullableDefault, String key) {
+        super(nullableDefault);
+        this.key = key;
+    }
+
+    protected Object postprocessParsedValue(String textContent) {
+        HashMap<String,String> map = Maps.newHashMap();
+        map.put(key, textContent);
+        return map;
+    }
+
+}
index 3e63b928848d617a2b9fbd29278a1eb5e7f7e88d..853197c0b089b7ca1dd32bdf09486a5b8b72f849 100644 (file)
@@ -8,10 +8,10 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
 
+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.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
@@ -44,6 +44,12 @@ public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingSt
     }
 
     public AttributeMappingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc) {
+
+        if(attributeIfc instanceof DependencyAttribute) {
+            serviceNameOfDepAttr = ((DependencyAttribute)attributeIfc).getDependency().getSie().getQName().getLocalName();
+            namespaceOfDepAttr = ((DependencyAttribute)attributeIfc).getDependency().getSie().getQName().getNamespace().toString();
+        }
+
         return switchAttribute(attributeIfc);
     }
 
@@ -56,45 +62,63 @@ public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingSt
     }
 
     @Override
-    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaAttribute(JavaAttribute attributeIfc) {
-
-        if (attributeIfc.getOpenType() instanceof SimpleType<?>)
-            return new SimpleAttributeMappingStrategy((SimpleType<?>) attributeIfc.getOpenType());
-        else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
-            ArrayType<?> arrayType = (ArrayType<?>) attributeIfc.getOpenType();
-            AttributeMappingStrategy<?, ? extends OpenType<?>> innerStrategy = new SimpleAttributeMappingStrategy(
-                    (SimpleType<?>) arrayType.getElementOpenType());
-            return new ArrayAttributeMappingStrategy(arrayType, innerStrategy);
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaSimpleAttribute(SimpleType<?> openType) {
+        return new SimpleAttributeMappingStrategy(openType);
+    }
+
+    @Override
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaArrayAttribute(ArrayType<?> openType) {
+
+        AttributeMappingStrategy<?, ? extends OpenType<?>> innerStrategy = new SimpleAttributeMappingStrategy(
+                (SimpleType<?>) openType.getElementOpenType());
+        return new ArrayAttributeMappingStrategy(openType, innerStrategy);
+    }
+
+    @Override
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaCompositeAttribute(CompositeType openType) {
+        Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
+
+        Map<String, String> attributeMapping = Maps.newHashMap();
+
+        for (String innerAttributeKey : openType.keySet()) {
+
+            innerStrategies.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey)));
+            attributeMapping.put(innerAttributeKey, innerAttributeKey);
         }
-        throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
-                + " or " + ArrayType.class);
+
+        return new CompositeAttributeMappingStrategy(openType, innerStrategies, attributeMapping);
     }
 
+    private String serviceNameOfDepAttr;
+    private String namespaceOfDepAttr;
+
     @Override
     protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseDependencyAttribute(
-            DependencyAttribute attributeIfc) {
-        String serviceName = attributeIfc.getDependency().getSie().getQName().getLocalName();
-        String namespace = attributeIfc.getDependency().getSie().getQName().getNamespace().toString();
-        return new ObjectNameAttributeMappingStrategy((SimpleType<?>) attributeIfc.getOpenType(), dependencyTracker,
-                serviceName, namespace);
+            SimpleType<?> openType) {
+        return new ObjectNameAttributeMappingStrategy(openType, dependencyTracker,
+                serviceNameOfDepAttr, namespaceOfDepAttr);
     }
 
     @Override
-    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseTOAttribute(TOAttribute attributeIfc) {
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseTOAttribute(CompositeType openType) {
         Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> innerStrategies = Maps.newHashMap();
 
-        for (Entry<String, AttributeIfc> innerAttrEntry : attributeIfc.getJmxPropertiesToTypesMap().entrySet()) {
+        Preconditions.checkState(lastAttribute instanceof TOAttribute);
+        TOAttribute lastTO = (TOAttribute) lastAttribute;
+
+        for (Entry<String, AttributeIfc> innerAttrEntry : ((TOAttribute)lastAttribute).getJmxPropertiesToTypesMap().entrySet()) {
             innerStrategies.put(innerAttrEntry.getKey(), prepareStrategy(innerAttrEntry.getValue()));
         }
 
-        return new CompositeAttributeMappingStrategy((CompositeType) attributeIfc.getOpenType(), innerStrategies,
-                createJmxToYangMapping(attributeIfc));
+        return new CompositeAttributeMappingStrategy(openType, innerStrategies,
+                createJmxToYangMapping(lastTO));
     }
 
     @Override
-    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListAttribute(ListAttribute attributeIfc) {
-        return new ArrayAttributeMappingStrategy(attributeIfc.getOpenType(),
-                prepareStrategy(attributeIfc.getInnerAttribute()));
+    protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseListAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListAttribute);
+        return new ArrayAttributeMappingStrategy(openType,
+                prepareStrategy(((ListAttribute) lastAttribute).getInnerAttribute()));
     }
 
 }
index 94a69477582fe379feb1e74552d7eb9a4411d362..c321164cf6b29c02548d9239787de2686d26e521 100644 (file)
@@ -8,29 +8,24 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
 
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
+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.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
 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;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import java.util.Map;
+import java.util.Map.Entry;
 
 public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvingStrategy<?, ? extends OpenType<?>>> {
 
     private final Services serviceTracker;
-    private OpenType<?> openType;
 
     public ObjectResolver(Services serviceTracker) {
         this.serviceTracker = serviceTracker;
@@ -42,16 +37,14 @@ public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvi
 
         for (Entry<String, AttributeIfc> attrEntry : configDefinition.entrySet()) {
             strategies.put(attrEntry.getKey(),
-                    prepareStrategy(attrEntry.getValue(), attrEntry.getValue().getOpenType()));
+                    prepareStrategy(attrEntry.getValue()));
         }
 
         return strategies;
     }
 
-    private AttributeResolvingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc,
-            OpenType<?> openType) {
+    private AttributeResolvingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc) {
 
-        this.openType = openType;
         return switchAttribute(attributeIfc);
     }
 
@@ -64,45 +57,56 @@ public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvi
     }
 
     @Override
-    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaAttribute(JavaAttribute attributeIfc) {
-        if (attributeIfc.getOpenType() instanceof SimpleType<?>)
-            return new SimpleAttributeResolvingStrategy((SimpleType<?>) openType);
-        else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
-            ArrayType<?> arrayType = (ArrayType<?>) openType;
-            SimpleType<?> innerType = (SimpleType<?>) arrayType.getElementOpenType();
-            AttributeResolvingStrategy<?, ? extends OpenType<?>> strat = new SimpleAttributeResolvingStrategy(innerType);
-            return new ArrayAttributeResolvingStrategy(strat, arrayType);
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>>  caseJavaSimpleAttribute(SimpleType<?> openType) {
+        return new SimpleAttributeResolvingStrategy(openType);
+    }
+
+    @Override
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>>  caseJavaArrayAttribute(ArrayType<?> openType) {
+        SimpleType<?> innerType = (SimpleType<?>) openType.getElementOpenType();
+        AttributeResolvingStrategy<?, ? extends OpenType<?>> strat = new SimpleAttributeResolvingStrategy(innerType);
+        return new ArrayAttributeResolvingStrategy(strat, openType);
+    }
+
+    @Override
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>>  caseJavaCompositeAttribute(CompositeType openType) {
+        Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
+
+        Map<String, String> yangToJmxMapping = Maps.newHashMap();
+        for (String innerAttributeKey : openType.keySet()) {
+            innerMap.put(innerAttributeKey, caseJavaAttribute(openType.getType(innerAttributeKey)));
+            yangToJmxMapping.put(innerAttributeKey, innerAttributeKey);
         }
-        throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
-                + " or " + ArrayType.class);
+        return new CompositeAttributeResolvingStrategy(innerMap, openType, yangToJmxMapping);
     }
 
     @Override
     protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseDependencyAttribute(
-            DependencyAttribute attributeIfc) {
+            SimpleType<?> openType) {
         return new ObjectNameAttributeResolvingStrategy(serviceTracker);
     }
 
     @Override
-    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseTOAttribute(TOAttribute attributeIfc) {
-        CompositeType compositeType = (CompositeType) openType;
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseTOAttribute(CompositeType openType) {
+        Preconditions.checkState(lastAttribute instanceof TOAttribute);
+        TOAttribute toAttribute = (TOAttribute) lastAttribute;
+
         Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> innerMap = Maps.newHashMap();
-        for (String innerName : compositeType.keySet()) {
-            Preconditions.checkState(attributeIfc instanceof TOAttribute, "Unexpected state, " + attributeIfc
-                    + " should be instance of " + TOAttribute.class.getName());
-            AttributeIfc innerAttributeIfc = attributeIfc.getJmxPropertiesToTypesMap().get(innerName);
+
+        for (String innerName : openType.keySet()) {
+
+            AttributeIfc innerAttributeIfc = toAttribute.getJmxPropertiesToTypesMap().get(innerName);
             innerMap.put(innerAttributeIfc.getAttributeYangName(),
-                    prepareStrategy(innerAttributeIfc, compositeType.getType(innerName)));
+                    prepareStrategy(innerAttributeIfc));
         }
-        return new CompositeAttributeResolvingStrategy(innerMap, compositeType, createYangToJmxMapping(attributeIfc));
+        return new CompositeAttributeResolvingStrategy(innerMap, openType, createYangToJmxMapping(toAttribute));
     }
 
     @Override
-    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListAttribute(ListAttribute attributeIfc) {
-        ArrayType<?> arrayType = (ArrayType<?>) openType;
-        OpenType<?> innerType = arrayType.getElementOpenType();
-        AttributeIfc inner = attributeIfc.getInnerAttribute();
-        return new ArrayAttributeResolvingStrategy(prepareStrategy(inner, innerType), arrayType);
+    protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseListAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListAttribute);
+        AttributeIfc innerAttribute = ((ListAttribute) lastAttribute).getInnerAttribute();
+        return new ArrayAttributeResolvingStrategy(prepareStrategy(innerAttribute), openType);
     }
 
 }
index 4888dd029f727efe1bbc89e1419a57199376ad72..99e969970ccbd9ec27926979a5d597ab2b1f8881 100644 (file)
@@ -11,14 +11,13 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attri
 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.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
 import org.w3c.dom.Document;
 
 import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.SimpleType;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -52,28 +51,33 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritin
     }
 
     @Override
-    protected AttributeWritingStrategy caseJavaAttribute(JavaAttribute attributeIfc) {
+    protected AttributeWritingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
+        return new SimpleAttributeWritingStrategy(document, key);
+    }
 
-        if (attributeIfc.getOpenType() instanceof SimpleType<?>)
-            return new SimpleAttributeWritingStrategy(document, key);
-        else if (attributeIfc.getOpenType() instanceof ArrayType<?>) {
-            AttributeWritingStrategy innerStrategy = new SimpleAttributeWritingStrategy(document, key);
-            return new ArrayAttributeWritingStrategy(innerStrategy);
-        }
-        throw new IllegalStateException(JavaAttribute.class + " can only provide open type " + SimpleType.class
-                + " or " + ArrayType.class);
+    @Override
+    protected AttributeWritingStrategy caseJavaArrayAttribute(ArrayType<?> openType) {
+        AttributeWritingStrategy innerStrategy = new SimpleAttributeWritingStrategy(document, key);
+        return new ArrayAttributeWritingStrategy(innerStrategy);
     }
 
     @Override
-    protected AttributeWritingStrategy caseDependencyAttribute(DependencyAttribute attributeIfc) {
+    protected AttributeWritingStrategy caseJavaCompositeAttribute(CompositeType openType) {
+        return new SimpleCompositeAttributeWritingStrategy(document, key);
+    }
+
+    @Override
+    protected AttributeWritingStrategy caseDependencyAttribute(SimpleType<?> openType) {
         return new ObjectNameAttributeWritingStrategy(document, key);
     }
 
     @Override
-    protected AttributeWritingStrategy caseTOAttribute(TOAttribute attributeIfc) {
+    protected AttributeWritingStrategy caseTOAttribute(CompositeType openType) {
+        Preconditions.checkState(lastAttribute instanceof TOAttribute);
+
         Map<String, AttributeWritingStrategy> innerStrats = Maps.newHashMap();
         String currentKey = key;
-        for (Entry<String, AttributeIfc> innerAttrEntry : attributeIfc.getYangPropertiesToTypesMap().entrySet()) {
+        for (Entry<String, AttributeIfc> innerAttrEntry : ((TOAttribute) lastAttribute).getYangPropertiesToTypesMap().entrySet()) {
 
             AttributeWritingStrategy innerStrategy = prepareWritingStrategy(innerAttrEntry.getKey(),
                     innerAttrEntry.getValue(), document);
@@ -84,9 +88,11 @@ public class ObjectXmlWriter extends AttributeIfcSwitchStatement<AttributeWritin
     }
 
     @Override
-    protected AttributeWritingStrategy caseListAttribute(ListAttribute attributeIfc) {
-        AttributeIfc inner = attributeIfc.getInnerAttribute();
-        AttributeWritingStrategy innerStrategy = prepareWritingStrategy(key, inner, document);
+    protected AttributeWritingStrategy caseListAttribute(ArrayType<?> openType) {
+        Preconditions.checkState(lastAttribute instanceof ListAttribute);
+        AttributeIfc innerAttribute = ((ListAttribute) lastAttribute).getInnerAttribute();
+
+        AttributeWritingStrategy innerStrategy = prepareWritingStrategy(key, innerAttribute, document);
         return new ArrayAttributeWritingStrategy(innerStrategy);
     }
 
index 514183be2fef343b2a5f11888d9baa181e8c94de..62ff682a7fd7bbd2760e156150e22f1fb4457f51 100644 (file)
@@ -29,10 +29,16 @@ public class SimpleAttributeWritingStrategy implements AttributeWritingStrategy
 
     @Override
     public void writeElement(Element parentElement, String namespace, Object value) {
+        value = preprocess(value);
         Util.checkType(value, String.class);
         Element innerNode = XmlUtil.createTextElement(document, key, (String) value);
         XmlUtil.addNamespaceAttr(innerNode, namespace);
         parentElement.appendChild(innerNode);
     }
 
+    protected Object preprocess(Object value) {
+        return value;
+    }
+
+
 }
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleCompositeAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleCompositeAttributeWritingStrategy.java
new file mode 100644 (file)
index 0000000..10b643f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.confignetconfconnector.mapping.attributes.toxml;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.w3c.dom.Document;
+
+import java.util.Map;
+
+public class SimpleCompositeAttributeWritingStrategy extends SimpleAttributeWritingStrategy {
+
+    /**
+     * @param document
+     * @param key
+     */
+    public SimpleCompositeAttributeWritingStrategy(Document document, String key) {
+        super(document, key);
+    }
+
+    protected Object preprocess(Object value) {
+        Util.checkType(value, Map.class);
+        Preconditions.checkArgument(((Map)value).size() == 1, "Unexpected number of values in %s, expected 1", value);
+        return ((Map)value).values().iterator().next();
+    }
+
+}
index f96b3acf20c0f2d518ed042f9191fe33b7de798a..f33a32271fd189dd39a61b7403069d765e4d1615 100644 (file)
@@ -52,21 +52,24 @@ public class Config {
         this.moduleNamesToConfigs = Collections.unmodifiableMap(moduleNamesToConfigs);
     }
 
-    private Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
-            Services serviceTracker) {
+    public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
+                                                                                Services serviceTracker, Map<String, Map<String, ModuleConfig>> configs) {
         Multimap<String, ObjectName> moduleToInstances = mapInstancesToModules(instancesToMap);
 
         Map<String, Map<String, Collection<ObjectName>>> retVal = Maps.newLinkedHashMap();
 
-        for (String namespace : moduleConfigs.keySet()) {
+        for (String namespace : configs.keySet()) {
 
             Map<String, Collection<ObjectName>> innerRetVal = Maps.newHashMap();
 
-            for (Entry<String, ModuleConfig> mbeEntry : moduleConfigs.get(namespace).entrySet()) {
+            for (Entry<String, ModuleConfig> mbeEntry : configs.get(namespace).entrySet()) {
 
                 String moduleName = mbeEntry.getKey();
                 Collection<ObjectName> instances = moduleToInstances.get(moduleName);
 
+                // TODO, this code does not support same module names from different namespaces
+                // Namespace should be present in ObjectName
+
                 if (instances == null)
                     continue;
 
@@ -86,7 +89,7 @@ public class Config {
         return retVal;
     }
 
-    private void addServices(Services serviceTracker, Collection<ObjectName> instances,
+    private static void addServices(Services serviceTracker, Collection<ObjectName> instances,
             Multimap<String, String> providedServices) {
         for (ObjectName instanceOn : instances) {
             for (Entry<String, String> serviceName : providedServices.entries()) {
@@ -115,7 +118,7 @@ public class Config {
         Services serviceTracker = new Services();
 
         Map<String, Map<String, Collection<ObjectName>>> moduleToInstances = getMappedInstances(instancesToMap,
-                serviceTracker);
+                serviceTracker, moduleConfigs);
 
         Element root = dataElement;
         if (maybeNamespace.isPresent()) {
index 4dbfba119f865980daf18ac49b3564bfddff996c..11e97ebdbb9fc27c63e87d71c9962bcc494217ce 100644 (file)
@@ -9,8 +9,8 @@
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime;
 
 import com.google.common.collect.Sets;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -40,17 +40,10 @@ public class ModuleRuntime {
         throw new IllegalStateException("Root runtime bean not found among " + runtimeBeanOns);
     }
 
-    public Element toXml(String namespace, String instanceName, Collection<ObjectName> runtimeBeanOns, Document document) {
-        Element moduleElement = document.createElement(XmlNetconfConstants.MODULE_KEY);
+    public Element toXml(String namespace, Collection<ObjectName> runtimeBeanOns,
+                         Document document, ModuleConfig moduleConfig, ObjectName configBeanON, Services serviceTracker) {
 
-        final String prefix = getPrefix(namespace);
-        Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlNetconfConstants.TYPE_KEY, prefix,
-                moduleName);
-        XmlUtil.addPrefixedNamespaceAttr(typeElement, prefix, namespace);
-        moduleElement.appendChild(typeElement);
-
-        Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName);
-        moduleElement.appendChild(nameElement);
+        Element moduleElement = moduleConfig.toXml(configBeanON, serviceTracker, document, namespace);
 
         ObjectName rootName = findRoot(runtimeBeanOns);
 
@@ -62,8 +55,4 @@ public class ModuleRuntime {
         return moduleElement;
     }
 
-    private String getPrefix(String namespace) {
-        return XmlNetconfConstants.PREFIX;
-    }
-
 }
index 8af1e0ee90e94fe7c009eb93ece4b1f478b16d4f..64f295a4d885f784a1f2c6a0ddaea915bc19ee8e 100644 (file)
@@ -12,26 +12,37 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Services;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 import javax.management.ObjectName;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
 public class Runtime {
 
     private final Map<String, Map<String, ModuleRuntime>> moduleRuntimes;
+    private final Map<String, Map<String, ModuleConfig>> moduleConfigs;
 
-    public Runtime(Map<String, Map<String, ModuleRuntime>> moduleRuntimes) {
+    public Runtime(Map<String, Map<String, ModuleRuntime>> moduleRuntimes,
+            Map<String, Map<String, ModuleConfig>> moduleConfigs) {
         this.moduleRuntimes = moduleRuntimes;
+        this.moduleConfigs = moduleConfigs;
     }
 
     private Map<String, Multimap<String, ObjectName>> mapInstancesToModules(Set<ObjectName> instancesToMap) {
         Map<String, Multimap<String, ObjectName>> retVal = Maps.newHashMap();
 
+        // TODO map to namepsace, prevent module name conflicts
+        // this code does not support same module names from different namespaces
+        // Namespace should be present in ObjectName
+
         for (ObjectName objectName : instancesToMap) {
             String moduleName = ObjectNameUtil.getFactoryName(objectName);
 
@@ -49,7 +60,9 @@ public class Runtime {
         return retVal;
     }
 
-    public Element toXml(Set<ObjectName> instancesToMap, Document document) {
+    public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document) {
+        Services serviceTracker = new Services();
+
         Element root = document.createElement(XmlNetconfConstants.DATA_KEY);
 
         Element modulesElement = document.createElement(XmlNetconfConstants.MODULES_KEY);
@@ -57,19 +70,30 @@ public class Runtime {
                 XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
         root.appendChild(modulesElement);
 
-        Map<String, Multimap<String, ObjectName>> moduleToInstances = mapInstancesToModules(instancesToMap);
+        Map<String, Multimap<String, ObjectName>> moduleToRuntimeInstance = mapInstancesToModules(instancesToMap);
+        Map<String, Map<String, Collection<ObjectName>>> moduleToConfigInstance = Config.getMappedInstances(
+                configBeans, serviceTracker, moduleConfigs);
+
+        for (String localNamespace : moduleConfigs.keySet()) {
+
+            Map<String, Collection<ObjectName>> instanceToMbe = moduleToConfigInstance.get(localNamespace);
 
-        for (String localNamespace : moduleRuntimes.keySet()) {
-            for (String moduleName : moduleRuntimes.get(localNamespace).keySet()) {
-                Multimap<String, ObjectName> instanceToRbe = moduleToInstances.get(moduleName);
+            for (String moduleName : moduleConfigs.get(localNamespace).keySet()) {
+                Multimap<String, ObjectName> instanceToRbe = moduleToRuntimeInstance.get(moduleName);
 
-                if (instanceToRbe == null)
-                    continue;
+                for (ObjectName instanceON : instanceToMbe.get(moduleName)) {
+                    String instanceName = ObjectNameUtil.getInstanceName(instanceON);
 
-                for (String instanceName : instanceToRbe.keySet()) {
-                    ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName);
-                    Element innerXml = moduleRuntime.toXml(localNamespace, instanceName, instanceToRbe.get(instanceName), document);
-                    modulesElement.appendChild(innerXml);
+                    Element runtimeXml;
+                    ModuleConfig moduleConfig = moduleConfigs.get(localNamespace).get(moduleName);
+                    if(instanceToRbe==null || instanceToRbe.containsKey(instanceName) == false) {
+                        runtimeXml = moduleConfig.toXml(instanceON, serviceTracker, document, localNamespace);
+                    } else {
+                        ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName);
+                        runtimeXml = moduleRuntime.toXml(localNamespace, instanceToRbe.get(instanceName), document,
+                                moduleConfig, instanceON, serviceTracker);
+                    }
+                    modulesElement.appendChild(runtimeXml);
                 }
 
             }
@@ -78,4 +102,14 @@ public class Runtime {
         return root;
     }
 
+    private ObjectName findInstance(Collection<ObjectName> objectNames, String instanceName) {
+        for (ObjectName objectName : objectNames) {
+            String name = ObjectNameUtil.getInstanceName(objectName);
+            if(name.equals(instanceName))
+                return objectName;
+        }
+
+        throw new UnsupportedOperationException("Unable to find config bean instance under name " + instanceName + " among " + objectNames);
+    }
+
 }
index 101af48a8934f82c6daeee71b46d93a517605f5c..1fca16433a9ac7d1e3af41c64c9167138b5afd65 100644 (file)
@@ -193,7 +193,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
         } catch (IllegalStateException e) {
             logger.warn("Error parsing xml", e);
             final Map<String, String> errorInfo = new HashMap<>();
-            errorInfo.put(ErrorTag.missing_attribute.name(), "Missing value for 'target' attribute");
+            errorInfo.put(ErrorTag.missing_attribute.name(), "Error parsing xml: " + e.getMessage());
             throw new NetconfDocumentedException(e.getMessage(), ErrorType.rpc, ErrorTag.missing_attribute,
                     ErrorSeverity.error, errorInfo);
         } catch (final IllegalArgumentException e) {
index b93843d28e65a09aa62c9c5518209a5b0f772712..84a9f395207d0c6afcf3d3199cbb31abebd61f85 100644 (file)
@@ -18,10 +18,13 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorS
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.InstanceRuntime;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.ModuleRuntime;
 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.Runtime;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.slf4j.Logger;
@@ -129,12 +132,21 @@ public class Get extends AbstractConfigNetconfOperation {
             throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application,
                     ErrorTag.operation_not_supported, ErrorSeverity.error, errorInfo);
         }
+
         final Set<ObjectName> runtimeBeans = configRegistryClient.lookupRuntimeBeans();
-        final Map<String, Map<String, ModuleRuntime>> moduleMappings = createModuleRuntimes(configRegistryClient,
+
+        //Transaction provider required only for candidate datastore
+        final Set<ObjectName> configBeans = Datastore.getInstanceQueryStrategy(Datastore.running, null)
+                .queryInstances(configRegistryClient);
+
+        final Map<String, Map<String, ModuleRuntime>> moduleRuntimes = createModuleRuntimes(configRegistryClient,
                 yangStoreSnapshot.getModuleMXBeanEntryMap());
-        final Runtime runtime = new Runtime(moduleMappings);
+        final Map<String, Map<String, ModuleConfig>> moduleConfigs = GetConfig.transform(configRegistryClient,
+                yangStoreSnapshot.getModuleMXBeanEntryMap());
+
+        final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
 
-        final Element element = runtime.toXml(runtimeBeans, document);
+        final Element element = runtime.toXml(runtimeBeans, configBeans, document);
 
         logger.info("{} operation successful", GET);
 
index 79b3e26aec7b22bf188b67c3b13d39cfb7569f05..f2dfc7079c869d5f8db32db4550e677bdca8a19f 100644 (file)
@@ -91,7 +91,7 @@ public class GetConfig extends AbstractConfigNetconfOperation {
     }
 
     // TODO refactor ... duplicate code
-    private Map<String, Map<String, ModuleConfig>> transform(final ConfigRegistryClient configRegistryClient,
+    public static Map<String, Map<String, ModuleConfig>> transform(final ConfigRegistryClient configRegistryClient,
             Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
         return Maps.transformEntries(mBeanEntries,
                 new Maps.EntryTransformer<String, Map<String, ModuleMXBeanEntry>, Map<String, ModuleConfig>>() {
index 296b224fffbbc2e33fccc898dd78dcd204267d46..73d39c616221403737d5cfe7f52315b043fc19d5 100644 (file)
@@ -18,40 +18,22 @@ import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.api.runtime.RootRuntimeBeanRegistrator;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
 import org.opendaylight.controller.config.yang.store.impl.MbeParser;
-import org.opendaylight.controller.config.yang.test.impl.Asdf;
 import org.opendaylight.controller.config.yang.test.impl.ComplexDtoBInner;
 import org.opendaylight.controller.config.yang.test.impl.ComplexList;
 import org.opendaylight.controller.config.yang.test.impl.Deep;
-import org.opendaylight.controller.config.yang.test.impl.Deep2;
-import org.opendaylight.controller.config.yang.test.impl.Deep3;
-import org.opendaylight.controller.config.yang.test.impl.Deep4;
 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.DtoAInner;
 import org.opendaylight.controller.config.yang.test.impl.DtoAInnerInner;
 import org.opendaylight.controller.config.yang.test.impl.DtoC;
 import org.opendaylight.controller.config.yang.test.impl.DtoD;
-import org.opendaylight.controller.config.yang.test.impl.InnerInnerRunningDataRuntimeMXBean;
-import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataAdditionalRuntimeMXBean;
-import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataRuntimeMXBean;
-import org.opendaylight.controller.config.yang.test.impl.InnerRunningDataRuntimeRegistration;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
-import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeMXBean;
-import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeRegistration;
-import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeRegistrator;
-import org.opendaylight.controller.config.yang.test.impl.NotStateBean;
-import org.opendaylight.controller.config.yang.test.impl.NotStateBeanInternal;
 import org.opendaylight.controller.config.yang.test.impl.Peers;
-import org.opendaylight.controller.config.yang.test.impl.RetValContainer;
-import org.opendaylight.controller.config.yang.test.impl.RetValList;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
@@ -143,7 +125,6 @@ public class NetconfMappingTest extends AbstractConfigTest {
         edit("netconfMessages/editConfig.xml");
         checkBinaryLeafEdited(getConfigCandidate());
 
-
         // default-operation:none, should not affect binary leaf
         edit("netconfMessages/editConfig_none.xml");
         checkBinaryLeafEdited(getConfigCandidate());
@@ -154,6 +135,8 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
         checkBinaryLeafEdited(response);
         checkTypeConfigAttribute(response);
+        checkTypedefs(response);
+        checkEnum(response);
 
         edit("netconfMessages/editConfig_remove.xml");
 
@@ -375,7 +358,34 @@ public class NetconfMappingTest extends AbstractConfigTest {
             buf.append(XmlElement.fromDomElement(e).getTextContent());
         }
         assertEquals("810", buf.toString());
+    }
+
+    private void checkTypedefs(final Element response) {
+        NodeList children = response.getElementsByTagName("extended");
+        assertEquals(1, children.getLength());
 
+        children = response.getElementsByTagName("extended-twice");
+        assertEquals(1, children.getLength());
+    }
+
+    private void checkEnum(final Element response) {
+        XmlElement modulesElement = XmlElement.fromDomElement(response).getOnlyChildElement("data")
+                .getOnlyChildElement("modules");
+
+        String enumName = "extended-enum";
+        String enumContent = "TWO";
+
+        for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
+            String name = moduleElement.getOnlyChildElement("name").getTextContent();
+            if(name.equals("test1")) {
+                XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName);
+                assertEquals(enumContent, enumAttr.getTextContent());
+
+                return;
+            }
+        }
+
+        fail("Enum attribute " + enumName + ":" + enumContent + " not present in " + XmlUtil.toString(response));
     }
 
     private void checkTypeConfigAttribute(Element response) {
@@ -407,51 +417,28 @@ public class NetconfMappingTest extends AbstractConfigTest {
     @Test
     public void testConfigNetconfRuntime() throws Exception {
 
-        ModuleIdentifier id = new ModuleIdentifier(NetconfTestImplModuleFactory.NAME, "instance");
-        RootRuntimeBeanRegistrator rootReg = new RootRuntimeBeanRegistratorImpl(internalJmxRegistrator, id);
-        NetconfTestImplRuntimeRegistrator registrator = new NetconfTestImplRuntimeRegistrator(rootReg);
-
-        NetconfTestImplRuntimeRegistration a = registerRoot(registrator);
-        InnerRunningDataRuntimeRegistration reg = registerInner(a);
-        registerInner2(reg);
-
-        id = new ModuleIdentifier(NetconfTestImplModuleFactory.NAME, "instance2");
-        rootReg = new RootRuntimeBeanRegistratorImpl(internalJmxRegistrator, id);
-        registrator = new NetconfTestImplRuntimeRegistrator(rootReg);
-
-        a = registerRoot(registrator);
-        registerAdditional(a);
-        registerAdditional(a);
-        registerAdditional(a);
-        registerAdditional(a);
-        reg = registerInner(a);
-        registerInner2(reg);
-        reg = registerInner(a);
-        registerInner2(reg);
-        registerInner2(reg);
-        reg = registerInner(a);
-        registerInner2(reg);
-        registerInner2(reg);
-        registerInner2(reg);
-        reg = registerInner(a);
-        registerInner2(reg);
-        registerInner2(reg);
-        registerInner2(reg);
-        registerInner2(reg);
+        createModule(INSTANCE_NAME);
 
-        Element response = get();
+        edit("netconfMessages/editConfig.xml");
+        checkBinaryLeafEdited(getConfigCandidate());
 
-        System.err.println(XmlUtil.toString(response));
+        // check after edit
+        commit();
+        Element response = get();
 
-        assertEquals(2, getElementsSize(response, "module"));
+        assertEquals(2/*With runtime beans*/ + 2 /*Without runtime beans*/, getElementsSize(response, "module"));
+        // data from state
         assertEquals(2, getElementsSize(response, "asdf"));
-        assertEquals(5, getElementsSize(response, "inner-running-data"));
-        assertEquals(5, getElementsSize(response, "deep2"));
-        assertEquals(11, getElementsSize(response, "inner-inner-running-data"));
-        assertEquals(11, getElementsSize(response, "deep3"));
-        assertEquals(11 * 2, getElementsSize(response, "list-of-strings"));
-        assertEquals(4, getElementsSize(response, "inner-running-data-additional"));
-        assertEquals(4, getElementsSize(response, "deep4"));
+        // data from running config
+        assertEquals(2, getElementsSize(response, "simple-short"));
+
+        assertEquals(8, getElementsSize(response, "inner-running-data"));
+        assertEquals(8, getElementsSize(response, "deep2"));
+        assertEquals(8 * 4, getElementsSize(response, "inner-inner-running-data"));
+        assertEquals(8 * 4, getElementsSize(response, "deep3"));
+        assertEquals(8 * 4 * 2, getElementsSize(response, "list-of-strings"));
+        assertEquals(8, getElementsSize(response, "inner-running-data-additional"));
+        assertEquals(8, getElementsSize(response, "deep4"));
         // TODO assert keys
 
         RuntimeRpc netconf = new RuntimeRpc(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
@@ -479,153 +466,6 @@ public class NetconfMappingTest extends AbstractConfigTest {
         return response.getElementsByTagName(elementName).getLength();
     }
 
-    private Object registerAdditional(final NetconfTestImplRuntimeRegistration a) {
-        class InnerRunningDataAdditionalRuntimeMXBeanTest implements InnerRunningDataAdditionalRuntimeMXBean {
-
-            private final int simpleInt;
-            private final String simpleString;
-
-            public InnerRunningDataAdditionalRuntimeMXBeanTest(final int simpleInt, final String simpleString) {
-                this.simpleInt = simpleInt;
-                this.simpleString = simpleString;
-            }
-
-            @Override
-            public Integer getSimpleInt3() {
-                return this.simpleInt;
-            }
-
-            @Override
-            public Deep4 getDeep4() {
-                final Deep4 d = new Deep4();
-                d.setBoool(false);
-                return d;
-            }
-
-            @Override
-            public String getSimpleString() {
-                return this.simpleString;
-            }
-
-            @Override
-            public void noArgInner() {
-            }
-
-        }
-
-        final int simpleInt = counter++;
-        return a.register(new InnerRunningDataAdditionalRuntimeMXBeanTest(simpleInt, "randomString_" + simpleInt));
-    }
-
-    private void registerInner2(final InnerRunningDataRuntimeRegistration reg) {
-        class InnerInnerRunningDataRuntimeMXBeanTest implements InnerInnerRunningDataRuntimeMXBean {
-
-            private final int simpleInt;
-
-            public InnerInnerRunningDataRuntimeMXBeanTest(final int simpleInt) {
-                this.simpleInt = simpleInt;
-            }
-
-            @Override
-            public List<NotStateBean> getNotStateBean() {
-                final NotStateBean notStateBean = new NotStateBean();
-                final NotStateBeanInternal notStateBeanInternal = new NotStateBeanInternal();
-                notStateBean.setNotStateBeanInternal(Lists.newArrayList(notStateBeanInternal));
-                return Lists.newArrayList(notStateBean);
-            }
-
-            @Override
-            public Integer getSimpleInt3() {
-                return this.simpleInt;
-            }
-
-            @Override
-            public Deep3 getDeep3() {
-                return new Deep3();
-            }
-
-            @Override
-            public List<String> getListOfStrings() {
-                return Lists.newArrayList("l1", "l2");
-            }
-
-            @Override
-            public List<RetValList> listOutput() {
-                return Lists.newArrayList(new RetValList());
-            }
-
-            @Override
-            public Boolean noArgInnerInner(Integer integer, Boolean aBoolean) {
-                return aBoolean;
-            }
-
-            @Override
-            public RetValContainer containerOutput() {
-                return new RetValContainer();
-            }
-
-            @Override
-            public List<String> leafListOutput() {
-                return Lists.newArrayList("1", "2");
-            }
-
-        }
-
-        reg.register(new InnerInnerRunningDataRuntimeMXBeanTest(counter++));
-
-    }
-
-    private static int counter = 1000;
-
-    private InnerRunningDataRuntimeRegistration registerInner(final NetconfTestImplRuntimeRegistration a) {
-
-        class InnerRunningDataRuntimeMXBeanTest implements InnerRunningDataRuntimeMXBean {
-
-            private final int simpleInt;
-
-            public InnerRunningDataRuntimeMXBeanTest(final int simpleInt) {
-                this.simpleInt = simpleInt;
-            }
-
-            @Override
-            public Integer getSimpleInt3() {
-                return this.simpleInt;
-            }
-
-            @Override
-            public Deep2 getDeep2() {
-                return new Deep2();
-            }
-
-        }
-        return a.register(new InnerRunningDataRuntimeMXBeanTest(counter++));
-    }
-
-    private NetconfTestImplRuntimeRegistration registerRoot(final NetconfTestImplRuntimeRegistrator registrator) {
-        final NetconfTestImplRuntimeRegistration a = registrator.register(new NetconfTestImplRuntimeMXBean() {
-
-            @Override
-            public Long getCreatedSessions() {
-                return 11L;
-            }
-
-            @Override
-            public Asdf getAsdf() {
-                final Asdf asdf = new Asdf();
-                asdf.setSimpleInt(55);
-                asdf.setSimpleString("asdf");
-                return asdf;
-            }
-
-            @Override
-            public String noArg(final String arg1) {
-                return arg1.toUpperCase();
-            }
-
-        });
-        return a;
-    }
-
     private Element executeOp(final NetconfOperation op, final String filename) throws ParserConfigurationException,
             SAXException, IOException, NetconfDocumentedException {
 
@@ -643,7 +483,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
     private List<InputStream> getYangs() throws FileNotFoundException {
         List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
-                "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang",
+                "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang", "/META-INF/yang/test-types.yang",
                 "/META-INF/yang/ietf-inet-types.yang");
         final Collection<InputStream> yangDependencies = new ArrayList<>();
         for (String path : paths) {
index 21ecd3133949f2665a7132a417b929951692efc5..ce25de215e69d3a285d819e8ad3354f8fbdb91b3 100644 (file)
             <version>${bgpcep.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -72,7 +77,6 @@
                             javax.management,
                             javax.xml.parsers,
                             org.opendaylight.controller.config.persist.api,
-                            org.opendaylight.controller.config.persist.api.storage,
                             org.opendaylight.controller.netconf.api,
                             org.opendaylight.controller.netconf.api.jmx,
                             org.opendaylight.controller.netconf.client,
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java
new file mode 100644 (file)
index 0000000..d9c5dfa
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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.annotations.VisibleForTesting;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import static com.google.common.base.Preconditions.checkState;
+
+public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHolder {
+    private static final Logger logger = LoggerFactory.getLogger(CapabilityStrippingConfigSnapshotHolder.class);
+
+    private final String configSnapshot;
+    private final StripCapabilitiesResult stripCapabilitiesResult;
+
+    public CapabilityStrippingConfigSnapshotHolder(Element snapshot, Set<String> capabilities, Pattern ignoredMissingCapabilityRegex) {
+        final XmlElement configElement = XmlElement.fromDomElement(snapshot);
+        configSnapshot = XmlUtil.toString(configElement.getDomElement());
+        stripCapabilitiesResult = stripCapabilities(configElement, capabilities, ignoredMissingCapabilityRegex);
+    }
+
+    private static class StripCapabilitiesResult {
+        private final SortedSet<String> requiredCapabilities, missingNamespaces;
+
+        private StripCapabilitiesResult(SortedSet<String> requiredCapabilities, SortedSet<String> missingNamespaces) {
+            this.requiredCapabilities = Collections.unmodifiableSortedSet(requiredCapabilities);
+            this.missingNamespaces = Collections.unmodifiableSortedSet(missingNamespaces);
+        }
+    }
+
+
+    @VisibleForTesting
+    static StripCapabilitiesResult stripCapabilities(XmlElement configElement, Set<String> allCapabilitiesFromHello,
+                                                     Pattern ignoredMissingCapabilityRegex) {
+        // collect all namespaces
+        Set<String> foundNamespacesInXML = getNamespaces(configElement);
+        logger.trace("All capabilities {}\nFound namespaces in XML {}", allCapabilitiesFromHello, foundNamespacesInXML);
+        // required are referenced both in xml and hello
+        SortedSet<String> requiredCapabilities = new TreeSet<>();
+        // can be removed
+        Set<String> obsoleteCapabilities = new HashSet<>();
+        // are in xml but not in hello
+        SortedSet<String> missingNamespaces = new TreeSet<>(foundNamespacesInXML);
+        for (String capability : allCapabilitiesFromHello) {
+            String namespace = capability.replaceAll("\\?.*","");
+            if (foundNamespacesInXML.contains(namespace)) {
+                requiredCapabilities.add(capability);
+                checkState(missingNamespaces.remove(namespace));
+            } else {
+                obsoleteCapabilities.add(capability);
+            }
+        }
+
+        logger.trace("Required capabilities {}, \nObsolete capabilities {}",
+                requiredCapabilities, obsoleteCapabilities);
+
+        for(Iterator<String> iterator = missingNamespaces.iterator();iterator.hasNext(); ){
+            String capability = iterator.next();
+            if (ignoredMissingCapabilityRegex.matcher(capability).matches()){
+                logger.trace("Ignoring missing capability {}", capability);
+                iterator.remove();
+            }
+        }
+        if (missingNamespaces.size() > 0) {
+            logger.warn("Some capabilities are missing: {}", missingNamespaces);
+        }
+        return new StripCapabilitiesResult(requiredCapabilities, missingNamespaces);
+    }
+
+    static Set<String> getNamespaces(XmlElement element){
+        Set<String> result = new HashSet<>();
+        for (Entry<String,Attr> attribute : element.getAttributes().entrySet()) {
+            if  (attribute.getKey().startsWith("xmlns")){
+                result.add(attribute.getValue().getValue());
+            }
+        }
+        //element.getAttributes()
+        for(XmlElement child: element.getChildElements()) {
+            result.addAll(getNamespaces(child));
+        }
+        return result;
+    }
+
+    @Override
+    public SortedSet<String> getCapabilities() {
+        return stripCapabilitiesResult.requiredCapabilities;
+    }
+
+    @VisibleForTesting
+    Set<String> getMissingNamespaces(){
+        return stripCapabilitiesResult.missingNamespaces;
+    }
+
+    @Override
+    public String getConfigSnapshot() {
+        return configSnapshot;
+    }
+}
index 25d2ad6abd09943278d28262a7184649a0688f4f..a569f90538104048026249370a6650119007f32f 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
+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;
@@ -43,6 +44,7 @@ import java.net.InetSocketAddress;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 /**
  * Responsible for listening for notifications from netconf containing latest
@@ -53,6 +55,8 @@ import java.util.Set;
 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;
@@ -66,26 +70,29 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
 
     private final ObjectName on = DefaultCommitOperationMXBean.objectName;
 
-    public static final long DEFAULT_TIMEOUT = 40000L;
+    public static final long DEFAULT_TIMEOUT = 120000L;// 120 seconds until netconf must be stable
     private final long timeout;
+    private final Pattern ignoredMissingCapabilityRegex;
 
     public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
-            MBeanServerConnection mbeanServer) {
-        this(persister, address, mbeanServer, DEFAULT_TIMEOUT);
+            MBeanServerConnection mbeanServer, Pattern ignoredMissingCapabilityRegex) {
+        this(persister, address, mbeanServer, DEFAULT_TIMEOUT, ignoredMissingCapabilityRegex);
+
     }
 
     public ConfigPersisterNotificationHandler(Persister persister, InetSocketAddress address,
-            MBeanServerConnection mbeanServer, long timeout) {
+            MBeanServerConnection mbeanServer, long timeout, Pattern ignoredMissingCapabilityRegex) {
         this.persister = persister;
         this.address = address;
         this.mbeanServer = mbeanServer;
         this.timeout = timeout;
 
         this.nettyThreadgroup = new NioEventLoopGroup();
+        this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex;
     }
 
     public void init() throws InterruptedException {
-        Optional<Persister.ConfigSnapshotHolder> maybeConfig = loadLastConfig();
+        Optional<ConfigSnapshotHolder> maybeConfig = loadLastConfig();
 
         if (maybeConfig.isPresent()) {
             logger.debug("Last config found {}", persister);
@@ -93,6 +100,7 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
             registerToNetconf(maybeConfig.get().getCapabilities());
 
             final String configSnapshot = maybeConfig.get().getConfigSnapshot();
+            logger.trace("Pushing following xml to netconf {}", configSnapshot);
             try {
                 pushLastConfig(XmlUtil.readXmlToElement(configSnapshot));
             } catch (SAXException | IOException e) {
@@ -219,26 +227,16 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
 
     private void handleAfterCommitNotification(final CommitJMXNotification notification) {
         try {
-            final XmlElement configElement = XmlElement.fromDomElement(notification.getConfigSnapshot());
-            persister.persistConfig(new Persister.ConfigSnapshotHolder() {
-                @Override
-                public String getConfigSnapshot() {
-                    return XmlUtil.toString(configElement.getDomElement());
-                }
-
-                @Override
-                public Set<String> getCapabilities() {
-                    return notification.getCapabilities();
-                }
-            });
+            persister.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
+                    notification.getCapabilities(), ignoredMissingCapabilityRegex));
             logger.debug("Configuration persisted successfully");
         } catch (IOException e) {
             throw new RuntimeException("Unable to persist configuration snapshot", e);
         }
     }
 
-    private Optional<Persister.ConfigSnapshotHolder> loadLastConfig() {
-        Optional<Persister.ConfigSnapshotHolder> maybeConfigElement;
+    private Optional<ConfigSnapshotHolder> loadLastConfig() {
+        Optional<ConfigSnapshotHolder> maybeConfigElement;
         try {
             maybeConfigElement = persister.loadLastConfig();
         } catch (IOException e) {
@@ -247,12 +245,15 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         return maybeConfigElement;
     }
 
-    private synchronized void pushLastConfig(Element persistedConfig) {
+    private synchronized void pushLastConfig(Element xmlToBePersisted) {
+        logger.info("Pushing last configuration to netconf");
         StringBuilder response = new StringBuilder("editConfig response = {");
 
-        Element configElement = persistedConfig;
-        NetconfMessage message = createEditConfigMessage(configElement, "/netconfOp/editConfig.xml");
-        NetconfMessage responseMessage = netconfClient.sendMessage(message);
+
+        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));
@@ -261,7 +262,7 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         checkIsOk(element, responseMessage);
         response.append(XmlUtil.toString(responseMessage.getDocument()));
         response.append("}");
-        responseMessage = netconfClient.sendMessage(getNetconfMessageFromResource("/netconfOp/commit.xml"));
+        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));
@@ -271,7 +272,8 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         response.append("commit response = {");
         response.append(XmlUtil.toString(responseMessage.getDocument()));
         response.append("}");
-        logger.debug("Last configuration loaded successfully");
+        logger.info("Last configuration loaded successfully");
+        logger.trace("Detailed message {}", response);
     }
 
     private void checkIsOk(XmlElement element, NetconfMessage responseMessage) {
@@ -289,8 +291,8 @@ public class ConfigPersisterNotificationHandler implements NotificationListener,
         }
     }
 
-    private NetconfMessage createEditConfigMessage(Element dataElement, String editConfigResourcename) {
-        try (InputStream stream = getClass().getResourceAsStream(editConfigResourcename)) {
+    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);
index cd604312f4d0318fa2f55ed637e00c01b392e206..b37c1457c330ee73467e48950144bf3ee237ccbc 100644 (file)
@@ -9,19 +9,22 @@
 package org.opendaylight.controller.netconf.persist.impl;
 
 import com.google.common.base.Optional;
-import org.opendaylight.controller.config.persist.api.storage.StorageAdapter;
-import org.osgi.framework.BundleContext;
+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 org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 
-public class NoOpStorageAdapter implements StorageAdapter {
+public class NoOpStorageAdapter implements StorageAdapter, Persister {
     private static final Logger logger = LoggerFactory.getLogger(NoOpStorageAdapter.class);
 
     @Override
-    public void setProperties(BundleContext bundleContext) {
-        logger.debug("setProperties called with {}", bundleContext);
+    public Persister instantiate(PropertiesProvider propertiesProvider) {
+        logger.debug("instantiate called with {}", propertiesProvider);
+        return this;
     }
 
     @Override
@@ -36,7 +39,7 @@ public class NoOpStorageAdapter implements StorageAdapter {
     }
 
     @Override
-    public void close() throws IOException {
+    public void close() {
         logger.debug("close called");
     }
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
new file mode 100644 (file)
index 0000000..7add448
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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.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;
+import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
+import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * {@link Persister} implementation that delegates persisting functionality to
+ * underlying {@link Persister} storages. Each storage has unique id, class, readonly value.
+ *
+ * Storage adapters are low level persisters that do the heavy lifting for this
+ * class. Instances of storage adapters can be injected directly via constructor
+ * or instantiated from a full name of its class provided in a properties file.
+ *
+ * Example configuration:<pre>
+ netconf.config.persister.active=2,3
+ # read startup configuration
+ netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter
+ netconf.config.persister.1.properties.fileStorage=configuration/initial/
+
+ netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+ netconf.config.persister.2.readonly=true
+ netconf.config.persister.2.properties.fileStorage=configuration/current/controller.config.1.txt
+
+ netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
+ netconf.config.persister.3.properties.fileStorage=configuration/current/controller.config.2.txt
+ netconf.config.persister.3.properties.numberOfBackups=3
+
+ </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
+ * specified (first '3', then '2').
+ *
+ * When a commit notification is received, '2' will be omitted because readonly flag is set to true, so
+ * only '3' will have a chance to persist new configuration. If readonly was false or not specified, both storage adapters
+ * would be called in order specified by 'netconf.config.persister' property.
+ *
+ */
+public final class PersisterAggregator implements Persister {
+    private static final Logger logger = LoggerFactory.getLogger(PersisterAggregator.class);
+
+    public static class PersisterWithConfiguration {
+
+        public final Persister storage;
+        private final boolean readOnly;
+
+        public PersisterWithConfiguration(Persister storage, boolean readOnly) {
+            this.storage = storage;
+            this.readOnly = readOnly;
+        }
+
+        @Override
+        public String toString() {
+            return "PersisterWithConfiguration{" +
+                    "storage=" + storage +
+                    ", readOnly=" + readOnly +
+                    '}';
+        }
+    }
+
+    private static PersisterWithConfiguration loadConfiguration(final String index, final PropertiesProviderBaseImpl propertiesProvider) {
+
+        String classKey = index + "." + ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX;
+        String storageAdapterClass = propertiesProvider.getProperty(classKey);
+        StorageAdapter storageAdapter;
+        if (storageAdapterClass == null || storageAdapterClass.equals("")) {
+            throw new IllegalStateException("No persister is defined in " +
+                    propertiesProvider.getFullKeyForReporting(classKey)
+                    + " property. Persister is not operational");
+        }
+
+        try {
+            Class<?> clazz = Class.forName(storageAdapterClass);
+            boolean implementsCorrectIfc = StorageAdapter.class.isAssignableFrom(clazz);
+            if (implementsCorrectIfc == false) {
+                throw new IllegalArgumentException("Storage adapter " + clazz + " does not implement " + StorageAdapter.class);
+            }
+            storageAdapter = StorageAdapter.class.cast(clazz.newInstance());
+
+            boolean readOnly = false;
+            String readOnlyProperty = propertiesProvider.getProperty(index + "." + "readonly");
+            if (readOnlyProperty != null && readOnlyProperty.equals("true")) {
+                readOnly = true;
+            }
+
+            PropertiesProviderAdapterImpl innerProvider = new PropertiesProviderAdapterImpl(propertiesProvider, index);
+            Persister storage = storageAdapter.instantiate(innerProvider);
+            return new PersisterWithConfiguration(storage, readOnly);
+        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+            throw new IllegalArgumentException("Unable to instantiate storage adapter from " + storageAdapterClass, e);
+        }
+    }
+
+    /**
+     * Persisters ordered by 'netconf.config.persister' property.
+     */
+    private final List<PersisterWithConfiguration> persisterWithConfigurations;
+
+    public PersisterAggregator(List<PersisterWithConfiguration> persisterWithConfigurations) {
+        this.persisterWithConfigurations = persisterWithConfigurations;
+
+    }
+
+    public static PersisterAggregator createFromProperties(PropertiesProviderBaseImpl propertiesProvider) {
+        List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
+        String prefixes = propertiesProvider.getProperty("active");
+        if (prefixes.isEmpty() == false) {
+            String [] keys = prefixes.split(",");
+            for (String index: keys) {
+                persisterWithConfigurations.add(PersisterAggregator.loadConfiguration(index, propertiesProvider));
+            }
+        }
+        logger.debug("Initialized persister with following adapters {}", persisterWithConfigurations);
+        return new PersisterAggregator(persisterWithConfigurations);
+    }
+
+    @Override
+    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+        for (PersisterWithConfiguration persisterWithConfiguration: persisterWithConfigurations){
+            if (!persisterWithConfiguration.readOnly){
+                logger.debug("Calling {}.persistConfig",persisterWithConfiguration.storage);
+                persisterWithConfiguration.storage.persistConfig(holder);
+            }
+        }
+    }
+
+    @Override
+    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+        // 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;
+            }
+        }
+        // no storage had an answer
+        return Optional.absent();
+    }
+
+    @VisibleForTesting
+    List<PersisterWithConfiguration> getPersisterWithConfigurations() {
+        return persisterWithConfigurations;
+    }
+
+    @Override
+    public void close() {
+        RuntimeException lastException = null;
+        for (PersisterWithConfiguration persisterWithConfiguration: persisterWithConfigurations){
+            try{
+                persisterWithConfiguration.storage.close();
+            }catch(RuntimeException e) {
+                logger.error("Error while closing {}", persisterWithConfiguration.storage, e);
+                if (lastException == null){
+                    lastException = e;
+                } else {
+                    lastException.addSuppressed(e);
+                }
+            }
+        }
+        if (lastException != null){
+            throw lastException;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "PersisterAggregator{" +
+                "persisterWithConfigurations=" + persisterWithConfigurations +
+                '}';
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterImpl.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterImpl.java
deleted file mode 100644 (file)
index e06968e..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.api.storage.StorageAdapter;
-import org.osgi.framework.BundleContext;
-
-import java.io.IOException;
-
-/**
- * {@link Persister} implementation that delegates persisting functionality to
- * underlying {@link Persister} called Storage Adapter.
- *
- * Storage adapters are low level persisters that do the heavy lifting for this
- * class. Instances of storage adapters can be injected directly via constructor
- * or instantiated from a full name of its class provided in a properties file.
- *
- * Name of storage adapter class should be located under
- * {@link #STORAGE_ADAPTER_CLASS_PROP} key.
- */
-public final class PersisterImpl implements Persister {
-
-    public static final String STORAGE_ADAPTER_CLASS_PROP = "netconf.config.persister.storageAdapterClass";
-    private final StorageAdapter storage;
-
-    public PersisterImpl(StorageAdapter storage) {
-        this.storage = storage;
-    }
-
-    public static Optional<PersisterImpl> createFromProperties(BundleContext bundleContext) {
-        String storageAdapterClass = bundleContext.getProperty(STORAGE_ADAPTER_CLASS_PROP);
-        StorageAdapter storage;
-        if (storageAdapterClass == null || storageAdapterClass.equals("")) {
-            return Optional.absent();
-        }
-
-        try {
-            storage = StorageAdapter.class.cast(resolveClass(storageAdapterClass, StorageAdapter.class).newInstance());
-            storage.setProperties(bundleContext);
-
-        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
-            throw new IllegalArgumentException("Unable to instantiate storage adapter from " + storageAdapterClass, e);
-        }
-        return Optional.of(new PersisterImpl(storage));
-    }
-
-    private static Class<?> resolveClass(String storageAdapterClass, Class<?> baseType) throws ClassNotFoundException {
-        Class<?> clazz = Class.forName(storageAdapterClass);
-
-        if (!isImplemented(baseType, clazz))
-            throw new IllegalArgumentException("Storage adapter " + clazz + " has to implement " + baseType);
-        return clazz;
-    }
-
-    private static boolean isImplemented(Class<?> expectedIface, Class<?> byClazz) {
-        for (Class<?> iface : byClazz.getInterfaces()) {
-            if (iface.equals(expectedIface))
-                return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
-        storage.persistConfig(holder);
-    }
-
-    @Override
-    public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
-        return storage.loadLastConfig();
-    }
-
-    @VisibleForTesting
-    StorageAdapter getStorage() {
-        return storage;
-    }
-
-    @Override
-    public void close() throws IOException {
-        storage.close();
-    }
-
-    @Override
-    public String toString() {
-        return "PersisterImpl [storage=" + storage + "]";
-    }
-}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PropertiesProviderAdapterImpl.java
new file mode 100644 (file)
index 0000000..981be82
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * @author Tomas Olvecky
+ *
+ * 11 2013
+ *
+ * Copyright (c) 2013 by Cisco Systems, Inc.
+ * All rights reserved.
+ */
+package org.opendaylight.controller.netconf.persist.impl;
+
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
+
+public class PropertiesProviderAdapterImpl implements PropertiesProvider {
+    private final PropertiesProviderBaseImpl inner;
+    private final String index;
+
+    public PropertiesProviderAdapterImpl(PropertiesProviderBaseImpl inner, String index) {
+        this.inner = inner;
+        this.index = index;
+    }
+
+    @Override
+    public String getProperty(String key) {
+        String fullKey = getFullKeyForReporting(key);
+        return inner.getPropertyWithoutPrefix(fullKey);
+    }
+
+    public String getPrefix() {
+        return inner.getPrefix() + "." + index + ".properties";
+    }
+
+    @Override
+    public String getFullKeyForReporting(String key) {
+        return getPrefix()  + "." + key;
+    }
+}
index ae6c95312c9143d29f384571ffe9182b227aa862..5fa0b49d7b954434e88220f5378ccc89d0f51f8d 100644 (file)
@@ -8,12 +8,9 @@
 
 package org.opendaylight.controller.netconf.persist.impl.osgi;
 
-import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
-import org.opendaylight.controller.netconf.persist.impl.NoOpStorageAdapter;
-import org.opendaylight.controller.netconf.persist.impl.PersisterImpl;
+import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
-import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.TLSConfiguration;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
@@ -22,43 +19,45 @@ import org.slf4j.LoggerFactory;
 import javax.management.MBeanServer;
 import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
+import java.util.regex.Pattern;
 
 public class ConfigPersisterActivator implements BundleActivator {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class);
 
     private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
+    private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
 
     private ConfigPersisterNotificationHandler configPersisterNotificationHandler;
 
     private Thread initializationThread;
 
-    @Override
-    public void start(BundleContext context) throws Exception {
-        logger.debug("ConfigPersister activator started");
+    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";
 
-        Optional<PersisterImpl> maybePersister = PersisterImpl.createFromProperties(context);
-        if (maybePersister.isPresent() == false) {
-            throw new IllegalStateException("No persister is defined in " + PersisterImpl.STORAGE_ADAPTER_CLASS_PROP
-                    + " property. For noop persister use " + NoOpStorageAdapter.class.getCanonicalName()
-                    + " . Persister is not operational");
-        }
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        logger.debug("ConfigPersister starting");
 
-        Optional<TLSConfiguration> maybeTLSConfiguration = NetconfConfigUtil.extractTLSConfiguration(context);
-        Optional<InetSocketAddress> maybeTCPAddress = NetconfConfigUtil.extractTCPNetconfAddress(context);
+        PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
 
-        InetSocketAddress address;
-        if (maybeTLSConfiguration.isPresent()) {
-            throw new UnsupportedOperationException("TLS is currently not supported for persister");
-        } else if (maybeTCPAddress.isPresent()) {
-            address = maybeTCPAddress.get();
+        String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX);
+        String regex;
+        if (regexProperty != null) {
+            regex = regexProperty;
         } else {
-            throw new IllegalStateException("Netconf is not configured, persister is not operational");
+            regex = DEFAULT_IGNORED_REGEX;
         }
+        Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
+        PersisterAggregator persister = PersisterAggregator.createFromProperties(propertiesProvider);
 
-        PersisterImpl persister = maybePersister.get();
+        InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
+                "Netconf is not configured, persister is not operational");
         configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(persister, address,
-                platformMBeanServer);
+                platformMBeanServer, ignoredMissingCapabilityRegex);
+
+        // offload initialization to another thread in order to stop blocking activator
         Runnable initializationRunnable = new Runnable() {
             @Override
             public void run() {
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/PropertiesProviderBaseImpl.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/PropertiesProviderBaseImpl.java
new file mode 100644 (file)
index 0000000..15ed5c4
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * @author Tomas Olvecky
+ *
+ * 11 2013
+ *
+ * Copyright (c) 2013 by Cisco Systems, Inc.
+ * All rights reserved.
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PropertiesProviderBaseImpl implements PropertiesProvider {
+
+    private static final Logger logger = LoggerFactory.getLogger(PropertiesProviderBaseImpl.class);
+    private final BundleContext bundleContext;
+
+    public PropertiesProviderBaseImpl(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public String getProperty(String key) {
+        String fullKey = getFullKeyForReporting(key);
+        return getPropertyWithoutPrefix(fullKey);
+    }
+
+    public String getPropertyWithoutPrefix(String fullKey){
+        logger.trace("Full key {}", fullKey);
+        return bundleContext.getProperty(fullKey);
+    }
+
+    public String getPrefix(){
+        return ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER;
+    }
+
+    @Override
+    public String getFullKeyForReporting(String key) {
+        return getPrefix() + "." + key;
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java
new file mode 100644 (file)
index 0000000..d91712f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.collect.Sets;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Element;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.assertEquals;
+
+public class CapabilityStrippingConfigSnapshotHolderTest {
+
+    @Test
+    public void  testCapabilityStripping() throws Exception {
+        Set<String> allCapabilities = readLines("/capabilities-all.txt");
+        Set<String> expectedCapabilities = readLines("/capabilities-stripped.txt");
+        String snapshotAsString = readToString("/snapshot.xml");
+        Element element = XmlUtil.readXmlToElement(snapshotAsString);
+        {
+            CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder(
+                    element, allCapabilities, Pattern.compile(
+                    ConfigPersisterActivator.DEFAULT_IGNORED_REGEX
+            ));
+            assertEquals(expectedCapabilities, tested.getCapabilities());
+            assertEquals(Collections.emptySet(), tested.getMissingNamespaces());
+        }
+        {
+            // test regex
+            CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder(
+                    element, allCapabilities, Pattern.compile(
+                    "^bar"
+            ));
+            assertEquals(expectedCapabilities, tested.getCapabilities());
+            assertEquals(Sets.newHashSet(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX.substring(1)),
+                    tested.getMissingNamespaces());
+        }
+    }
+
+    private Set<String> readLines(String fileName) throws IOException {
+        return new HashSet<>(IOUtils.readLines(getClass().getResourceAsStream(fileName)));
+    }
+
+    private String readToString(String fileName) throws IOException {
+        return IOUtils.toString(getClass().getResourceAsStream(fileName));
+    }
+
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregatorTest.java
new file mode 100644 (file)
index 0000000..1b4031a
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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 org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+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 org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter;
+import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
+import org.opendaylight.controller.netconf.persist.impl.osgi.PropertiesProviderBaseImpl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class PersisterAggregatorTest {
+    @Mock
+    TestingPropertiesProvider propertiesProvider;
+
+    class TestingPropertiesProvider extends PropertiesProviderBaseImpl {
+        TestingPropertiesProvider() {
+            super(null);
+        }
+
+        @Override
+        public String getFullKeyForReporting(String key) {
+            return "prefix." + key;
+        }
+
+        @Override
+        public String getProperty(String key) {
+            throw new UnsupportedOperationException("should be mocked");
+        }
+    }
+
+    @Before
+    public void setUpMocks() {
+        MockitoAnnotations.initMocks(this);
+        doCallRealMethod().when(propertiesProvider).getFullKeyForReporting(anyString());
+    }
+
+    @Ignore
+    @Test
+    public void testFromProperties() throws Exception {
+        doReturn("").when(propertiesProvider).getProperty(ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER);
+        doReturn(MockAdapter.class.getName()).when(propertiesProvider).getProperty(
+                ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX);
+        doReturn("false").when(propertiesProvider).getProperty("readOnly");
+
+        PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
+        persisterAggregator.persistConfig(null);
+        persisterAggregator.loadLastConfig();
+        persisterAggregator.persistConfig(null);
+        persisterAggregator.loadLastConfig();
+
+        assertEquals(2, MockAdapter.persist);
+        assertEquals(2, MockAdapter.load);
+        assertEquals(1, MockAdapter.props);
+    }
+
+
+    @Ignore
+    @Test
+    public void testFromProperties2() throws Exception {
+        String prefix = "";
+        doReturn(prefix).when(propertiesProvider).getProperty(ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER);
+        doReturn(FileStorageAdapter.class.getName()).when(propertiesProvider).getProperty(
+                ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX);
+
+        doReturn("target" + File.separator + "generated-test-sources" + File.separator + "testFile").when(
+                propertiesProvider).getProperty("prefix.properties.fileStorage");
+        doReturn("propertiesProvider").when(propertiesProvider).toString();
+        doReturn(null).when(propertiesProvider).getProperty("prefix.properties.numberOfBackups");
+
+        PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
+    }
+
+    @Ignore
+    @Test
+    public void testFromProperties3() throws Exception {
+        doReturn("").when(propertiesProvider).getProperty(ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER);
+        doReturn(FileStorageAdapter.class.getName()).when(propertiesProvider).getProperty(
+                ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX);
+        doReturn("target" + File.separator + "generated-test-sources" + File.separator + "testFile").when(
+                propertiesProvider).getProperty("prefix.properties.fileStorage");
+        doReturn("false").when(propertiesProvider).getProperty("readOnly");
+        doReturn("propertiesProvider").when(propertiesProvider).toString();
+        doReturn("0").when(propertiesProvider).getProperty("prefix.properties.numberOfBackups");
+        try {
+            PersisterAggregator.createFromProperties(propertiesProvider);
+            fail();
+        } catch (RuntimeException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("numberOfBackups property should be either set to positive value, or ommited. Can not be set to 0."));
+        }
+    }
+
+    @Test
+    public void loadLastConfig() throws Exception {
+        List<PersisterAggregator.PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
+        PersisterAggregator.PersisterWithConfiguration first = new PersisterAggregator.PersisterWithConfiguration(mock(Persister.class), false);
+
+        ConfigSnapshotHolder ignored = mock(ConfigSnapshotHolder.class);
+        doReturn(Optional.of(ignored)).when(first.storage).loadLastConfig(); // should be ignored
+
+        ConfigSnapshotHolder used = mock(ConfigSnapshotHolder.class);
+        PersisterAggregator.PersisterWithConfiguration second = new PersisterAggregator.PersisterWithConfiguration(mock(Persister.class), false);
+        doReturn(Optional.of(used)).when(second.storage).loadLastConfig(); // should be used
+
+        PersisterAggregator.PersisterWithConfiguration third = new PersisterAggregator.PersisterWithConfiguration(mock(Persister.class), false);
+        doReturn(Optional.absent()).when(third.storage).loadLastConfig();
+
+        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());
+    }
+
+    @Ignore
+    @Test
+    public void test() throws Exception {
+//        Persister storage = mock(Persister.class);
+//        doReturn(null).when(storage).loadLastConfig();
+//        doNothing().when(storage).persistConfig(any(ConfigSnapshotHolder.class));
+//
+//        PersisterAggregator persister = new PersisterAggregator(storage);
+//        persister.loadLastConfig();
+//        persister.persistConfig(null);
+//
+//        verify(storage).loadLastConfig();
+//        verify(storage).persistConfig(any(ConfigSnapshotHolder.class));
+    }
+
+    public static class MockAdapter implements StorageAdapter, Persister {
+
+        static int persist = 0;
+
+        @Override
+        public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
+            persist++;
+        }
+
+        static int load = 0;
+
+        @Override
+        public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
+            load++;
+            return Optional.absent();
+        }
+
+        static int props = 0;
+
+        @Override
+        public Persister instantiate(PropertiesProvider propertiesProvider) {
+            props++;
+            return this;
+        }
+
+        @Override
+        public void close() {
+        }
+
+    }
+
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterImplTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/PersisterImplTest.java
deleted file mode 100644 (file)
index 44b3b61..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.persist.impl;
-
-import com.google.common.base.Optional;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.api.storage.StorageAdapter;
-import org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter;
-import org.osgi.framework.BundleContext;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class PersisterImplTest {
-    @Mock
-    BundleContext mockedContext;
-
-    @Before
-    public void setUpMocks() {
-        MockitoAnnotations.initMocks(this);
-    }
-
-    @Test
-    public void testFromProperties() throws Exception {
-        doReturn(MockAdapter.class.getName()).when(mockedContext).getProperty(
-                PersisterImpl.STORAGE_ADAPTER_CLASS_PROP);
-
-        PersisterImpl persisterImpl = PersisterImpl.createFromProperties(mockedContext).get();
-        persisterImpl.persistConfig(null);
-        persisterImpl.loadLastConfig();
-        persisterImpl.persistConfig(null);
-        persisterImpl.loadLastConfig();
-
-        assertEquals(2, MockAdapter.persist);
-        assertEquals(2, MockAdapter.load);
-        assertEquals(1, MockAdapter.props);
-    }
-
-    @Test
-    public void testFromProperties2() throws Exception {
-        mockedContext = mock(BundleContext.class);
-        doReturn(FileStorageAdapter.class.getName()).when(mockedContext).getProperty(
-                PersisterImpl.STORAGE_ADAPTER_CLASS_PROP);
-        doReturn("target" + File.separator + "generated-test-sources" + File.separator + "testFile").when(
-                mockedContext).getProperty(FileStorageAdapter.FILE_STORAGE_PROP);
-        doReturn("mockedContext").when(mockedContext).toString();
-        doReturn(null).when(mockedContext).getProperty("numberOfBackups");
-
-        PersisterImpl persisterImpl = PersisterImpl.createFromProperties(mockedContext).get();
-        assertTrue(persisterImpl.getStorage() instanceof FileStorageAdapter);
-    }
-
-    @Test
-    public void testFromProperties3() throws Exception {
-        mockedContext = mock(BundleContext.class);
-        doReturn(FileStorageAdapter.class.getName()).when(mockedContext).getProperty(
-                PersisterImpl.STORAGE_ADAPTER_CLASS_PROP);
-        doReturn("target" + File.separator + "generated-test-sources" + File.separator + "testFile").when(
-                mockedContext).getProperty(FileStorageAdapter.FILE_STORAGE_PROP);
-        doReturn("mockedContext").when(mockedContext).toString();
-        doReturn("0").when(mockedContext).getProperty("numberOfBackups");
-        try {
-            PersisterImpl.createFromProperties(mockedContext).get();
-            fail();
-        } catch (RuntimeException e) {
-            assertThat(
-                    e.getMessage(),
-                    containsString("numberOfBackups property should be either set to positive value, or ommited. Can not be set to 0."));
-        }
-    }
-
-    @Test
-    public void test() throws Exception {
-        StorageAdapter storage = mock(StorageAdapter.class);
-        doReturn(null).when(storage).loadLastConfig();
-        doNothing().when(storage).persistConfig(any(Persister.ConfigSnapshotHolder.class));
-        PersisterImpl persister = new PersisterImpl(storage);
-        persister.loadLastConfig();
-        persister.persistConfig(null);
-
-        verify(storage).loadLastConfig();
-        verify(storage).persistConfig(any(Persister.ConfigSnapshotHolder.class));
-    }
-
-    public static class MockAdapter implements StorageAdapter {
-
-        static int persist = 0;
-
-        @Override
-        public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
-            persist++;
-        }
-
-        static int load = 0;
-
-        @Override
-        public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
-            load++;
-            return null;// ?
-        }
-
-        static int props = 0;
-
-        @Override
-        public void setProperties(BundleContext configProvider) {
-            props++;
-        }
-
-        @Override
-        public void close() throws IOException {
-            // TODO Auto-generated method stub
-
-        }
-
-    }
-
-}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/resources/capabilities-all.txt b/opendaylight/netconf/config-persister-impl/src/test/resources/capabilities-all.txt
new file mode 100644 (file)
index 0000000..84c85b7
--- /dev/null
@@ -0,0 +1,20 @@
+urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
+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/netconf/config-persister-impl/src/test/resources/capabilities-stripped.txt b/opendaylight/netconf/config-persister-impl/src/test/resources/capabilities-stripped.txt
new file mode 100644 (file)
index 0000000..4a0b7ff
--- /dev/null
@@ -0,0 +1,5 @@
+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: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:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
+urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
diff --git a/opendaylight/netconf/config-persister-impl/src/test/resources/logback-test.xml b/opendaylight/netconf/config-persister-impl/src/test/resources/logback-test.xml
new file mode 100644 (file)
index 0000000..a4ff3ab
--- /dev/null
@@ -0,0 +1,13 @@
+<configuration scan="true">
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="error">
+        <appender-ref ref="STDOUT" />
+    </root>
+    <logger name="org.opendaylight.controller.netconf.persist.impl" level="TRACE"/>
+</configuration>
diff --git a/opendaylight/netconf/config-persister-impl/src/test/resources/snapshot.xml b/opendaylight/netconf/config-persister-impl/src/test/resources/snapshot.xml
new file mode 100644 (file)
index 0000000..a6a57d7
--- /dev/null
@@ -0,0 +1,103 @@
+<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>
+        <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: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>
+        <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 8b761a85b23b423314a39f8718492a2f5d1f8de0..17330b7babde5ce12030568ffca5d12207edb946 100644 (file)
@@ -9,10 +9,6 @@ package org.opendaylight.controller.netconf.api;
 
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
-
-import java.io.IOException;
-import java.util.Map;
-
 import org.opendaylight.protocol.framework.AbstractProtocolSession;
 import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
 import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
@@ -20,18 +16,20 @@ import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.util.Map;
+
 public abstract class NetconfSession extends AbstractProtocolSession<NetconfMessage> {
 
     private ChannelHandler exiEncoder;
     private String exiEncoderName;
     private String removeAfterMessageSentname;
     private String pmeName,pmdName;
-    private final  Channel channel;
+    protected final  Channel channel;
     private final  SessionListener sessionListener;
     private final long sessionId;
     private boolean up = false;
     private static final Logger logger = LoggerFactory.getLogger(NetconfSession.class);
-    private static final int T = 0;
 
     protected NetconfSession(SessionListener sessionListener, Channel channel, long sessionId) {
         this.sessionListener = sessionListener;
index ffd46e882c60f4a86b47470159d18139863ffff9..de4fb101f9d6fefb065e26f4b03bd46af4979cf3 100644 (file)
                             javax.xml.xpath,
                             org.opendaylight.controller.netconf.api,
                             org.opendaylight.controller.netconf.util,
-                            org.opendaylight.controller.netconf.util.xml,
+                            org.opendaylight.controller.netconf.util.*,
                             org.opendaylight.protocol.framework,
                             org.slf4j,
                             org.w3c.dom,
-                            org.xml.sax
+                            org.xml.sax,
+                            io.netty.handler.codec
                         </Import-Package>
                     </instructions>
                 </configuration>
index 61a9a9b9548bc6eeb771dcf952c61e08e4a669f3..d95977492a9206fb0ff05d4e6229810b08dcda9a 100644 (file)
@@ -50,7 +50,6 @@ public class NetconfClient implements Closeable {
     private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
         this.label = clientLabelForLogging;
         dispatch = netconfClientDispatcher;
-
         sessionListener = new NetconfClientSessionListener();
         Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
         this.address = address;
index 11c7f3061f9e9b28f34926b482c60a8bbe51a26a..c2c8d38b9a8daa08804a686e75106f4a86a60a58 100644 (file)
@@ -9,14 +9,13 @@
 package org.opendaylight.controller.netconf.client;
 
 import io.netty.channel.Channel;
-
-import java.util.Collection;
-
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collection;
+
 public class NetconfClientSession extends NetconfSession {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
@@ -32,5 +31,4 @@ public class NetconfClientSession extends NetconfSession {
     public Collection<String> getServerCapabilities() {
         return capabilities;
     }
-
 }
index ce0f4274757ac37a1791569b29b95906ec26cd6b..b19c09263b9fa481c76307da0bb2dbebc310bb85 100644 (file)
 
 package org.opendaylight.controller.netconf.client;
 
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import javax.net.ssl.SSLContext;
+
+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.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
+import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
+import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
+import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
+import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
+import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.protocol.framework.SessionListenerFactory;
+
+import com.google.common.base.Optional;
+
+import io.netty.channel.ChannelHandler;
 import io.netty.channel.EventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.Promise;
 
 public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
 
-    public NetconfSshClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
-        super(null, bossGroup, workerGroup);
+    private AuthenticationHandler authHandler;
+    private HashedWheelTimer timer;
+    private NetconfClientSessionNegotiatorFactory negotatorFactory;
+
+    public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
+            EventLoopGroup workerGroup) {
+        super(Optional.<SSLContext> absent(), bossGroup, workerGroup);
+        this.authHandler = authHandler;
+        this.timer = new HashedWheelTimer();
+        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer);
+    }
+
+    @Override
+    public Future<NetconfClientSession> createClient(InetSocketAddress address,
+            final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) {
+        return super.createClient(address, strat, new PipelineInitializer<NetconfClientSession>() {
+
+            @Override
+            public void initializeChannel(SocketChannel arg0, Promise<NetconfClientSession> arg1) {
+                new NetconfSshClientInitializer(authHandler, negotatorFactory, sessionListener).initialize(arg0, arg1);
+            }
+
+        });
+    }
+
+    private static final class NetconfSshClientInitializer extends AbstractChannelInitializer {
+
+        private final NetconfHandlerFactory handlerFactory;
+        private final AuthenticationHandler authenticationHandler;
+        private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
+        private final NetconfClientSessionListener sessionListener;
+
+        public NetconfSshClientInitializer(AuthenticationHandler authHandler,
+                NetconfClientSessionNegotiatorFactory negotiatorFactory,
+                final NetconfClientSessionListener sessionListener) {
+            this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
+            this.authenticationHandler = authHandler;
+            this.negotiatorFactory = negotiatorFactory;
+            this.sessionListener = sessionListener;
+        }
+
+        @Override
+        public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+            try {
+                Invoker invoker = Invoker.subsystem("netconf");
+                ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
+                ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
+                ch.pipeline().addLast(handlerFactory.getDecoders());
+                initializeAfterDecoder(ch, promise);
+                ch.pipeline().addLast("frameEncoder",
+                        FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
+                ch.pipeline().addLast(handlerFactory.getEncoders());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+            ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() {
+                @Override
+                public SessionListener<NetconfMessage, NetconfClientSession, NetconfTerminationReason> getSessionListener() {
+                    return sessionListener;
+                }
+            }, ch, promise));
+
+        }
+    }
+
+    private static final class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
+
+        public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
+            super(msgFactory);
+        }
+
+        @Override
+        public ChannelHandler[] getEncoders() {
+            return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
+        }
+
+        @Override
+        public ChannelHandler[] getDecoders() {
+            return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
+        }
     }
 }
index 890bbe728804e469f0d2989253e6815ec1b85d06..b334c354fbd8749026e7a01447a775aee2d74c05 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFact
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
-import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.TLSConfiguration;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
@@ -30,9 +29,6 @@ public class NetconfImplActivator implements BundleActivator {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfImplActivator.class);
 
-    private Optional<InetSocketAddress> maybeTCPAddress;
-    private Optional<TLSConfiguration> maybeTLSConfiguration;
-
     private NetconfOperationServiceFactoryTracker factoriesTracker;
     private DefaultCommitNotificationProducer commitNot;
     private NetconfServerDispatcher dispatch;
@@ -41,11 +37,8 @@ public class NetconfImplActivator implements BundleActivator {
 
     @Override
     public void start(final BundleContext context) throws Exception {
-        maybeTCPAddress = NetconfConfigUtil.extractTCPNetconfAddress(context);
-        maybeTLSConfiguration = NetconfConfigUtil.extractTLSConfiguration(context);
-        if (maybeTCPAddress.isPresent() == false && maybeTLSConfiguration.isPresent() == false) {
-            throw new IllegalStateException("TCP nor TLS is configured, netconf not available.");
-        }
+        InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context, "TCP is not configured, netconf not available.");
+
         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
         factoriesTracker = new NetconfOperationServiceFactoryTracker(context, factoriesListener);
         factoriesTracker.open();
@@ -62,26 +55,13 @@ public class NetconfImplActivator implements BundleActivator {
 
         eventLoopGroup = new NioEventLoopGroup();
 
-        if (maybeTCPAddress.isPresent()) {
-            Optional<SSLContext> maybeSSLContext = Optional.absent();
-            InetSocketAddress address = maybeTCPAddress.get();
-            NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
-                    maybeSSLContext, serverNegotiatorFactory, listenerFactory);
-            dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
-
-            logger.info("Starting TCP netconf server at {}", address);
-            dispatch.createServer(address);
-        }
-        if (maybeTLSConfiguration.isPresent()) {
-            Optional<SSLContext> maybeSSLContext = Optional.of(maybeTLSConfiguration.get().getSslContext());
-            InetSocketAddress address = maybeTLSConfiguration.get().getAddress();
-            NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
-                    maybeSSLContext, serverNegotiatorFactory, listenerFactory);
-            dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
-
-            logger.info("Starting TLS netconf server at {}", address);
-            dispatch.createServer(address);
-        }
+        NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
+                Optional.<SSLContext>absent(), serverNegotiatorFactory, listenerFactory);
+        dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
+
+        logger.info("Starting TCP netconf server at {}", address);
+        dispatch.createServer(address);
+
     }
 
     @Override
index 13b0a1e570b122ae04a94e5b626b27e7c93f7b88..410d9a96aa4a254b043901e74d3e19d8b049ead3 100644 (file)
             <artifactId>yang-store-api</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-test</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-api</artifactId>
             <artifactId>config-netconf-connector</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>yang-test</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>config-manager</artifactId>
             <artifactId>netconf-mapping-api</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-ssh</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-util</artifactId>
                             <goal>test</goal>
                         </goals>
                         <configuration>
-                            <includes>
-                                <include>**/org/opendaylight/controller/netconf/it/*.java</include>
-                            </includes>
                             <skip>false</skip>
+                            <argLine>-Dlogback.configurationFile=${maven.test.dest}/logback.xml</argLine>
                         </configuration>
                     </execution>
                 </executions>
index c03254dba2bbda03677efc89c4eadd39e2024acc..65cc2b4e373a3f551633d1cb564461ab39e0b174 100644 (file)
@@ -8,6 +8,8 @@
 
 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;
@@ -15,26 +17,35 @@ 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;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+import javax.management.ObjectName;
+import javax.net.ssl.SSLContext;
+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.api.ModuleIdentifier;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
-import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
 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;
 import org.opendaylight.controller.config.yang.store.impl.HardcodedYangStoreService;
-import org.opendaylight.controller.config.yang.test.impl.Asdf;
 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
-import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeMXBean;
-import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeRegistrator;
 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.client.NetconfClient;
@@ -49,43 +60,35 @@ import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;
 import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;
 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.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.ExiParameters;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 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.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
-
-import javax.management.ObjectName;
-import javax.net.ssl.SSLContext;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
+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 static org.mockito.internal.util.Checks.checkNotNull;
 
 public class NetconfITTest extends AbstractConfigTest {
 
-    // private static final Logger logger =
-    // LoggerFactory.getLogger(NetconfITTest.class);
+     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);
+    private static final String USERNAME = "netconf";
+    private static final String PASSWORD = "netconf";
 
     private NetconfMessage getConfig, getConfigCandidate, editConfig,
             closeSession, startExi, stopExi;
@@ -95,6 +98,7 @@ public class NetconfITTest extends AbstractConfigTest {
 
     private NetconfClientDispatcher clientDispatcher;
 
+
     @Before
     public void setUp() throws Exception {
         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(getModuleFactories().toArray(
@@ -155,13 +159,19 @@ public class NetconfITTest extends AbstractConfigTest {
 
     static Collection<InputStream> getBasicYangs() throws IOException {
         List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
-                "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang",
+                "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang", "/META-INF/yang/test-types.yang",
                 "/META-INF/yang/ietf-inet-types.yang");
         final Collection<InputStream> yangDependencies = new ArrayList<>();
+        List<String> failedToFind = new ArrayList<>();
         for (String path : paths) {
-            final InputStream is = checkNotNull(NetconfITTest.class.getResourceAsStream(path), path + " not found");
-            yangDependencies.add(is);
+            InputStream resourceAsStream = NetconfITTest.class.getResourceAsStream(path);
+            if (resourceAsStream == null) {
+                failedToFind.add(path);
+            } else {
+                yangDependencies.add(resourceAsStream);
+            }
         }
+        assertEquals("Some yang files were not found",emptyList(), failedToFind);
         return yangDependencies;
     }
 
@@ -190,8 +200,8 @@ public class NetconfITTest extends AbstractConfigTest {
 
     @Test
     public void testTwoSessions() throws Exception {
-        try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 4000, clientDispatcher))  {
-            try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 4000, clientDispatcher))  {
+        try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher))  {
+            try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 10000, clientDispatcher)) {
             }
         }
     }
@@ -201,7 +211,8 @@ public class NetconfITTest extends AbstractConfigTest {
         Persister persister = mock(Persister.class);
         doReturn("mockPersister").when(persister).toString();
         doReturn(Optional.absent()).when(persister).loadLastConfig();
-        ConfigPersisterNotificationHandler h = new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer());
+        ConfigPersisterNotificationHandler h =
+                new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(), Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
         h.init();
     }
 
@@ -264,7 +275,7 @@ public class NetconfITTest extends AbstractConfigTest {
         NetconfTestImplModuleMXBean proxy = configRegistryClient
                 .newMXBeanProxy(impl, NetconfTestImplModuleMXBean.class);
         proxy.setTestingDep(dep);
-        registerRuntimeBean();
+        proxy.setSimpleShort((short)0);
 
         transaction.commit();
 
@@ -289,29 +300,6 @@ public class NetconfITTest extends AbstractConfigTest {
         }
     }
 
-    private void registerRuntimeBean() {
-        BaseJMXRegistrator baseJMXRegistrator = new BaseJMXRegistrator(ManagementFactory.getPlatformMBeanServer());
-        RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = baseJMXRegistrator
-                .createRuntimeBeanRegistrator(new ModuleIdentifier(NetconfTestImplModuleFactory.NAME, "instance"));
-        NetconfTestImplRuntimeRegistrator reg = new NetconfTestImplRuntimeRegistrator(runtimeBeanRegistrator);
-        reg.register(new NetconfTestImplRuntimeMXBean() {
-            @Override
-            public Asdf getAsdf() {
-                return null;
-            }
-
-            @Override
-            public Long getCreatedSessions() {
-                return null;
-            }
-
-            @Override
-            public String noArg(String arg1) {
-                return "from no arg";
-            }
-        });
-    }
-
     @Test
 //    @Ignore
     public void testStartExi() throws Exception {
@@ -445,4 +433,46 @@ public class NetconfITTest extends AbstractConfigTest {
         return netconfClient;
     }
 
+    private void startSSHServer() throws Exception{
+        logger.info("Creating SSH server");
+        Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress));
+        sshServerThread.setDaemon(true);
+        sshServerThread.start();
+        logger.info("SSH server on");
+    }
+
+    @Test
+    public void sshTest() throws Exception {
+        startSSHServer();
+        logger.info("creating connection");
+        Connection conn = new Connection(sshAddress.getHostName(),sshAddress.getPort());
+        Assert.assertNotNull(conn);
+        logger.info("connection created");
+        conn.connect();
+        boolean isAuthenticated = conn.authenticateWithPassword(USERNAME,PASSWORD);
+        assertTrue(isAuthenticated);
+        logger.info("user authenticated");
+        final Session sess = conn.openSession();
+        sess.startSubSystem("netconf");
+        logger.info("user authenticated");
+        sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes());
+
+        new Thread(){
+           public void run(){
+               while (true){
+                 byte[] bytes = new byte[1024];
+                   int c = 0;
+                   try {
+                       c = sess.getStdout().read(bytes);
+                   } catch (IOException e) {
+                       e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+                   }
+                   logger.info("got data:"+bytes);
+                 if (c == 0) break;
+               }
+           }
+        }.join();
+    }
+
+
 }
diff --git a/opendaylight/netconf/netconf-it/src/test/resources/logback.xml b/opendaylight/netconf/netconf-it/src/test/resources/logback.xml
new file mode 100644 (file)
index 0000000..fa467a1
--- /dev/null
@@ -0,0 +1,15 @@
+<configuration scan="true">
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+  <logger name="org.opendaylight.controller.netconf" level="DEBUG"/>
+
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+  </root>
+
+</configuration>
diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml
new file mode 100644 (file)
index 0000000..794bb16
--- /dev/null
@@ -0,0 +1,84 @@
+<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>
+        <relativePath>../</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>netconf-ssh</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.thirdparty</groupId>
+            <artifactId>ganymed</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.controller.netconf.osgi.NetconfSSHActivator</Bundle-Activator>
+                        <Export-Package>
+                            org.opendaylight.controller.netconf.ssh,
+                        </Export-Package>
+                        <Import-Package>
+                            com.google.common.base,
+                            com.google.common.collect,
+                            ch.ethz.ssh2,
+                            ch.ethz.ssh2.signature,
+                            io.netty.buffer,
+                            io.netty.channel,
+                            io.netty.channel.nio,
+                            io.netty.channel.socket,
+                            io.netty.util,
+                            io.netty.util.concurrent,
+                            javax.annotation,
+                            java.net,
+                            javax.net.ssl,
+                            javax.xml.namespace,
+                            javax.xml.parsers,
+                            javax.xml.xpath,
+                            org.apache.commons.io,
+                            org.opendaylight.controller.netconf.api,
+                            org.opendaylight.controller.netconf.client,
+                            org.opendaylight.controller.netconf.util,
+                            org.opendaylight.controller.netconf.util.osgi,
+                            org.opendaylight.controller.netconf.util.xml,
+                            org.opendaylight.protocol.framework,
+                            org.osgi.framework,
+                            org.slf4j,
+                            org.w3c.dom,
+                            org.xml.sax
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java
new file mode 100644 (file)
index 0000000..d2f6c8c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.osgi;
+
+import com.google.common.base.Optional;
+import java.net.InetSocketAddress;
+import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
+ * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket
+ * and listen for client connections. Each client connection creation is handled in separate
+ * {@link org.opendaylight.controller.netconf.ssh.threads.SocketThread} thread.
+ * This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}
+ * forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream.
+ * {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}'s run method waits for -1 on input stream to finish.
+ * All threads are daemons.
+ **/
+public class NetconfSSHActivator implements BundleActivator{
+
+    private NetconfSSHServer server;
+    private static final Logger logger =  LoggerFactory.getLogger(NetconfSSHActivator.class);
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+
+        logger.trace("Starting netconf SSH  bridge.");
+
+        Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context);
+        InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
+                "TCP is not configured, netconf ssh bridge is not available.");
+
+        if (sshSocketAddressOptional.isPresent()){
+            server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress);
+            Thread serverThread = new  Thread(server,"netconf SSH server thread");
+            serverThread.setDaemon(true);
+            serverThread.start();
+            logger.trace("Netconf SSH  bridge up and running.");
+        } else {
+            logger.trace("No valid connection configuration for SSH bridge found.");
+            throw new Exception("No valid connection configuration for SSH bridge found.");
+        }
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        if (server != null){
+            logger.trace("Netconf SSH bridge going down ...");
+            server.stop();
+            logger.trace("Netconf SSH bridge is down ...");
+        }
+    }
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java
new file mode 100644 (file)
index 0000000..72135cc
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.ssh;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.controller.netconf.ssh.threads.SocketThread;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@ThreadSafe
+public class NetconfSSHServer implements Runnable {
+
+    private static boolean acceptMore = true;
+    private ServerSocket ss = null;
+    private static final Logger logger =  LoggerFactory.getLogger(NetconfSSHServer.class);
+    private static final AtomicLong sesssionId = new AtomicLong();
+    private final InetSocketAddress clientAddress;
+
+    private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress) throws Exception{
+
+        logger.trace("Creating SSH server socket on port {}",serverPort);
+        this.ss = new ServerSocket(serverPort);
+        if (!ss.isBound()){
+            throw new Exception("Socket can't be bound to requested port :"+serverPort);
+        }
+        logger.trace("Server socket created.");
+        this.clientAddress = clientAddress;
+
+    }
+
+
+    public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress) throws Exception {
+        return new NetconfSSHServer(serverPort, clientAddress);
+    }
+
+    public void stop() throws Exception {
+        acceptMore = false;
+        logger.trace("Closing SSH server socket.");
+        ss.close();
+        logger.trace("SSH server socket closed.");
+    }
+
+    @Override
+    public void run() {
+        while (acceptMore) {
+            logger.trace("Starting new socket thread.");
+            try {
+               SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet());
+            } catch (IOException e) {
+                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+            }
+        }
+    }
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java
new file mode 100644 (file)
index 0000000..59a911b
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 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.ssh.authentication;
+
+import ch.ethz.ssh2.signature.RSAPrivateKey;
+
+public interface KeyStoreHandler {
+    public RSAPrivateKey getPrivateKey();
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java
new file mode 100644 (file)
index 0000000..b420b33
--- /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.ssh.authentication;
+
+import ch.ethz.ssh2.signature.RSAPrivateKey;
+
+import java.math.BigInteger;
+
+public class RSAKey implements KeyStoreHandler {
+
+    private static RSAPrivateKey hostkey = null;
+    private static String user = "netconf";
+    private static String password = "netconf";
+    static {
+
+        BigInteger p = new BigInteger("2967886344240998436887630478678331145236162666668503940430852241825039192450179076148979094256007292741704260675085192441025058193581327559331546948442042987131728039318861235625879376246169858586459472691398815098207618446039");    //.BigInteger.probablePrime(N / 2, rnd);
+        BigInteger q = new BigInteger("4311534819291430017572425052029278681302539382618633848168923130451247487970187151403375389974616614405320169278870943605377518341666894603659873284783174749122655429409273983428000534304828056597676444751611433784228298909767"); //BigInteger.probablePrime(N / 2, rnd);
+        BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
+
+        BigInteger n = p.multiply(q);
+        BigInteger e = new BigInteger("65537");
+        BigInteger d = e.modInverse(phi);
+
+        hostkey = new RSAPrivateKey(d, e, n);
+    }
+
+    @Override
+    public RSAPrivateKey getPrivateKey() {
+        return hostkey;
+    }
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java
new file mode 100644 (file)
index 0000000..33ed88e
--- /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.ssh.threads;
+
+import ch.ethz.ssh2.ServerConnection;
+import ch.ethz.ssh2.ServerSession;
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.annotation.concurrent.ThreadSafe;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@ThreadSafe
+public class IOThread extends Thread {
+
+    private static final Logger logger =  LoggerFactory.getLogger(IOThread.class);
+
+    private InputStream inputStream;
+    private OutputStream outputStream;
+    private String id;
+    private ServerSession servSession;
+    private ServerConnection servconnection;
+
+
+    public IOThread (InputStream is, OutputStream os, String id,ServerSession ss, ServerConnection conn){
+        this.inputStream = is;
+        this.outputStream = os;
+        this.servSession = ss;
+        this.servconnection = conn;
+        super.setName(id);
+        logger.trace("IOThread {} created", super.getName());
+    }
+
+    @Override
+    public void run() {
+        logger.trace("thread {} started", super.getName());
+        try {
+            IOUtils.copy(this.inputStream, this.outputStream);
+        } catch (Exception e) {
+            logger.error("inputstream -> outputstream copy error ",e);
+        }
+        logger.trace("closing server session");
+        servSession.close();
+        servconnection.close();
+        logger.trace("thread {} is closing",super.getName());
+    }
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java
new file mode 100644 (file)
index 0000000..95fdd48
--- /dev/null
@@ -0,0 +1,176 @@
+package org.opendaylight.controller.netconf.ssh.threads;
+
+
+import ch.ethz.ssh2.AuthenticationResult;
+import ch.ethz.ssh2.PtySettings;
+import ch.ethz.ssh2.ServerAuthenticationCallback;
+import ch.ethz.ssh2.ServerConnection;
+import ch.ethz.ssh2.ServerConnectionCallback;
+import ch.ethz.ssh2.ServerSession;
+import ch.ethz.ssh2.ServerSessionCallback;
+import ch.ethz.ssh2.SimpleServerSessionCallback;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.controller.netconf.ssh.authentication.RSAKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@ThreadSafe
+public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback
+{
+
+    private Socket socket;
+    private static final String USER = "netconf";
+    private static final String PASSWORD = "netconf";
+    private InetSocketAddress clientAddress;
+    private static final Logger logger =  LoggerFactory.getLogger(SocketThread.class);
+    private ServerConnection conn = null;
+    private long sessionId;
+
+
+    public static void start(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException{
+        Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId));
+        netconf_ssh_socket_thread.setDaemon(true);
+        netconf_ssh_socket_thread.start();
+    }
+    private SocketThread(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException {
+
+        this.socket = socket;
+        this.clientAddress = clientAddress;
+        this.sessionId = sessionId;
+
+    }
+
+    @Override
+    public void run() {
+        conn = new ServerConnection(socket);
+        RSAKey keyStore = new RSAKey();
+        conn.setRsaHostKey(keyStore.getPrivateKey());
+        conn.setAuthenticationCallback(this);
+        conn.setServerConnectionCallback(this);
+        try {
+            conn.connect();
+        } catch (IOException e) {
+            logger.error("SocketThread error ",e);
+        }
+    }
+    public ServerSessionCallback acceptSession(final ServerSession session)
+    {
+        SimpleServerSessionCallback cb = new SimpleServerSessionCallback()
+        {
+            @Override
+            public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException
+            {
+                return new Runnable(){
+                    public void run()
+                    {
+                        if (subsystem.equals("netconf")){
+                            IOThread netconf_ssh_input = null;
+                            IOThread  netconf_ssh_output = null;
+                            try {
+                                String hostName = clientAddress.getHostName();
+                                int portNumber = clientAddress.getPort();
+                                final Socket echoSocket = new Socket(hostName, portNumber);
+                                logger.trace("echo socket created");
+
+                                logger.trace("starting netconf_ssh_input thread");
+                                netconf_ssh_input =  new IOThread(echoSocket.getInputStream(),ss.getStdin(),"input_thread_"+sessionId,ss,conn);
+                                netconf_ssh_input.setDaemon(false);
+                                netconf_ssh_input.start();
+
+                                logger.trace("starting netconf_ssh_output thread");
+                                netconf_ssh_output = new IOThread(ss.getStdout(),echoSocket.getOutputStream(),"output_thread_"+sessionId,ss,conn);
+                                netconf_ssh_output.setDaemon(false);
+                                netconf_ssh_output.start();
+
+                            } catch (Throwable t){
+                                logger.error(t.getMessage(),t);
+
+                                try {
+                                    if (netconf_ssh_input!=null){
+                                        netconf_ssh_input.join();
+                                    }
+                                } catch (InterruptedException e) {
+                                   logger.error("netconf_ssh_input join error ",e);
+                                }
+
+                                try {
+                                    if (netconf_ssh_output!=null){
+                                        netconf_ssh_output.join();
+                                    }
+                                } catch (InterruptedException e) {
+                                    logger.error("netconf_ssh_output join error ",e);
+                                }
+
+                            }
+                        } else {
+                            try {
+                                ss.getStdin().write("wrong subsystem requested - closing connection".getBytes());
+                                ss.close();
+                            } catch (IOException e) {
+                                logger.debug("excpetion while sending bad subsystem response",e);
+                            }
+                        }
+                    }
+                };
+            }
+            @Override
+            public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException
+            {
+                return new Runnable()
+                {
+                    public void run()
+                    {
+                        //noop
+                    }
+                };
+            }
+
+            @Override
+            public Runnable requestShell(final ServerSession ss) throws IOException
+            {
+                return new Runnable()
+                {
+                    public void run()
+                    {
+                        //noop
+                    }
+                };
+            }
+        };
+
+        return cb;
+    }
+
+    public String initAuthentication(ServerConnection sc)
+    {
+        return "";
+    }
+
+    public String[] getRemainingAuthMethods(ServerConnection sc)
+    {
+        return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD };
+    }
+
+    public AuthenticationResult authenticateWithNone(ServerConnection sc, String username)
+    {
+        return AuthenticationResult.FAILURE;
+    }
+
+    public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
+    {
+        if (USER.equals(username) && PASSWORD.equals(password))
+            return AuthenticationResult.SUCCESS;
+
+        return AuthenticationResult.FAILURE;
+    }
+
+    public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm,
+            byte[] publickey, byte[] signature)
+    {
+        return AuthenticationResult.FAILURE;
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java
new file mode 100644 (file)
index 0000000..54bc7bc
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.ssh;
+
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import junit.framework.Assert;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class SSHServerTest {
+
+    private static final String USER = "netconf";
+    private static final String PASSWORD  = "netconf";
+    private static final String HOST = "127.0.0.1";
+    private static final int PORT = 1830;
+    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 8383);
+    private static final Logger logger =  LoggerFactory.getLogger(SSHServerTest.class);
+
+//    @Before
+    public void startSSHServer() throws Exception{
+            logger.info("Creating SSH server");
+            NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress);
+            Thread sshServerThread = new Thread(server);
+            sshServerThread.setDaemon(true);
+            sshServerThread.start();
+            logger.info("SSH server on");
+    }
+
+    @Test
+    public void connect(){
+        Connection conn = new Connection(HOST,PORT);
+        Assert.assertNotNull(conn);
+        try {
+            logger.info("connecting to SSH server");
+            conn.connect();
+            logger.info("authenticating ...");
+            boolean isAuthenticated = conn.authenticateWithPassword(USER,PASSWORD);
+            Assert.assertTrue(isAuthenticated);
+            logger.info("opening session");
+            Session sess = conn.openSession();
+            logger.info("subsystem netconf");
+            sess.startSubSystem("netconf");
+            sess.getStdin().write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability></capabilities></hello>]]>]]>".getBytes());
+            IOUtils.copy(sess.getStdout(), System.out);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+}
index c19506b236a2d8b9cacdc7e03cc263f20a131bfb..353dd1aae70ba8eac0b8cb2fa9ca4ab21da5ba10 100644 (file)
@@ -76,6 +76,7 @@
                             org.opendaylight.controller.netconf.util.mapping,
                             org.opendaylight.controller.netconf.util.messages,
                             org.opendaylight.controller.netconf.util.handler,
+                            org.opendaylight.controller.netconf.util.handler.*,
                         </Export-Package>
                         <Import-Package>
                             com.google.common.base,
index b911989c646b64b139dd4a678cbd0c8adc03596d..0d9096c02a3abd1b33204665cb72dc4cbd10e805 100644 (file)
@@ -8,13 +8,16 @@
 
 package org.opendaylight.controller.netconf.util.handler.ssh;
 
+import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelOutboundHandlerAdapter;
 import io.netty.channel.ChannelPromise;
+
 import java.io.IOException;
 import java.net.SocketAddress;
+
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
 import org.opendaylight.controller.netconf.util.handler.ssh.client.SshClient;
@@ -50,7 +53,7 @@ public class SshHandler extends ChannelOutboundHandlerAdapter {
 
     @Override
     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
-        this.sshClientAdapter.write((String) msg);
+        this.sshClientAdapter.write((ByteBuf) msg);
     }
 
     @Override
index bb0d37899d7bfd0d5486d4ad22872f49313d4309..2f1b260bd087fd0f48dccdb0af1911157395d7cf 100644 (file)
@@ -13,7 +13,8 @@ import ch.ethz.ssh2.Connection;
 import java.io.IOException;
 
 /**
- * Class Providing username/password authentication option to {@link org.opendaylight.controller.netconf.util.handler.ssh.SshHandler}
+ * Class Providing username/password authentication option to
+ * {@link org.opendaylight.controller.netconf.util.handler.ssh.SshHandler}
  */
 public class LoginPassword extends AuthenticationHandler {
     private final String username;
@@ -28,6 +29,7 @@ public class LoginPassword extends AuthenticationHandler {
     public void authenticate(Connection connection) throws IOException {
         boolean isAuthenticated = connection.authenticateWithPassword(username, password);
 
-        if (isAuthenticated == false) throw new IOException("Authentication failed.");
+        if (isAuthenticated == false)
+            throw new IOException("Authentication failed.");
     }
 }
index c43aa6f3e59db1a57cf5a4166e61bfb0416a310f..3cb608db6a87c3ef121cc6a4edf0f0676fab9912 100644 (file)
@@ -18,7 +18,6 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
-
 /**
  * Wrapper class around GANYMED SSH java library.
  */
@@ -28,16 +27,16 @@ public class SshClient {
     private final AuthenticationHandler authenticationHandler;
     private Connection connection;
 
-    public SshClient(VirtualSocket socket,
-                     AuthenticationHandler authenticationHandler) throws IOException {
+    public SshClient(VirtualSocket socket, AuthenticationHandler authenticationHandler) throws IOException {
         this.socket = socket;
         this.authenticationHandler = authenticationHandler;
     }
 
     public SshSession openSession() throws IOException {
-        if(connection == null) connect();
+        if (connection == null)
+            connect();
 
-        Session session =  connection.openSession();
+        Session session = connection.openSession();
         SshSession sshSession = new SshSession(session);
         openSessions.put(openSessions.size(), sshSession);
 
@@ -46,22 +45,24 @@ public class SshClient {
 
     private void connect() throws IOException {
         connection = new Connection(socket);
+
         connection.connect();
         authenticationHandler.authenticate(connection);
     }
 
     public void closeSession(SshSession session) {
-        if(   session.getState() == Channel.STATE_OPEN
-           || session.getState() == Channel.STATE_OPENING) {
+        if (session.getState() == Channel.STATE_OPEN || session.getState() == Channel.STATE_OPENING) {
             session.session.close();
         }
     }
 
     public void close() {
-        for(SshSession session : openSessions.values()) closeSession(session);
+        for (SshSession session : openSessions.values())
+            closeSession(session);
 
         openSessions.clear();
 
-        if(connection != null) connection.close();
+        if (connection != null)
+            connection.close();
     }
 }
index a50462e40dae1e3c5ce40afd451713992ad28e2a..4213fe3e0642db6257b3e655c407a4394785fca3 100644 (file)
@@ -12,14 +12,19 @@ import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelPromise;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.LinkedList;
+import java.util.Queue;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.opendaylight.controller.netconf.util.handler.ssh.virtualsocket.VirtualSocketException;
 
+
 /**
- * Worker thread class. Handles all downstream and upstream events in SSH Netty pipeline.
+ * Worker thread class. Handles all downstream and upstream events in SSH Netty
+ * pipeline.
  */
 public class SshClientAdapter implements Runnable {
     private final SshClient sshClient;
@@ -30,6 +35,9 @@ public class SshClientAdapter implements Runnable {
     private InputStream stdErr;
     private OutputStream stdIn;
 
+    private Queue<ByteBuf> postponned = new LinkedList<>();
+
+
     private ChannelHandlerContext ctx;
     private ChannelPromise disconnectPromise;
 
@@ -37,8 +45,7 @@ public class SshClientAdapter implements Runnable {
 
     private final Object lock = new Object();
 
-    public SshClientAdapter(SshClient sshClient,
-                            Invoker invoker) {
+    public SshClientAdapter(SshClient sshClient, Invoker invoker) {
         this.sshClient = sshClient;
         this.invoker = invoker;
     }
@@ -47,18 +54,24 @@ public class SshClientAdapter implements Runnable {
         try {
             session = sshClient.openSession();
             invoker.invoke(session);
-
             stdOut = session.getStdout();
             stdErr = session.getStderr();
 
-            synchronized(lock) {
+            synchronized (lock) {
+
                 stdIn = session.getStdin();
+                ByteBuf message = null;
+                while ((message = postponned.poll()) != null) {
+                    writeImpl(message);
+                }
             }
 
             while (stopRequested.get() == false) {
                 byte[] readBuff = new byte[1024];
                 int c = stdOut.read(readBuff);
-
+                if (c == -1) {
+                    continue;
+                }
                 byte[] tranBuff = new byte[c];
                 System.arraycopy(readBuff, 0, tranBuff, 0, c);
 
@@ -76,17 +89,25 @@ public class SshClientAdapter implements Runnable {
             sshClient.close();
 
             synchronized (lock) {
-                if(disconnectPromise != null) ctx.disconnect(disconnectPromise);
+                if (disconnectPromise != null)
+                    ctx.disconnect(disconnectPromise);
             }
         }
     }
 
     // TODO: needs rework to match netconf framer API.
-    public void write(String message) throws IOException {
+    public void write(ByteBuf message) throws IOException {
         synchronized (lock) {
-            if (stdIn == null) throw new IllegalStateException("StdIn not available");
+            if (stdIn == null) {
+                postponned.add(message);
+                return;
+            }
+            writeImpl(message);
         }
-        stdIn.write(message.getBytes());
+    }
+
+    private void writeImpl(ByteBuf message) throws IOException {
+        message.getBytes(0, stdIn, message.readableBytes());
         stdIn.flush();
     }
 
@@ -98,8 +119,8 @@ public class SshClientAdapter implements Runnable {
     }
 
     public void start(ChannelHandlerContext ctx) {
-        if(this.ctx != null) return; // context is already associated.
-
+        if (this.ctx != null)
+            return; // context is already associated.
         this.ctx = ctx;
         new Thread(this).start();
     }
index 76068399c17f470b249c0ba35027f89d723b5d81..35e17a2a3e4564ffceac32158d00e5f7e6faba39 100644 (file)
@@ -26,7 +26,7 @@ public class NetconfConfigUtil {
     private static final String PREFIX_PROP = "netconf.";
 
     private enum InfixProp {
-        tcp, tls
+        tcp, tls, ssh
     }
 
     private static final String PORT_SUFFIX_PROP = ".port";
@@ -35,10 +35,20 @@ public class NetconfConfigUtil {
     private static final String NETCONF_TLS_KEYSTORE_PROP = PREFIX_PROP + InfixProp.tls + ".keystore";
     private static final String NETCONF_TLS_KEYSTORE_PASSWORD_PROP = NETCONF_TLS_KEYSTORE_PROP + ".password";
 
-    public static Optional<InetSocketAddress> extractTCPNetconfAddress(BundleContext context) {
-        return extractSomeNetconfAddress(context, InfixProp.tcp);
+    public static InetSocketAddress extractTCPNetconfAddress(BundleContext context, String exceptionMessageIfNotFound) {
+
+        Optional<InetSocketAddress> inetSocketAddressOptional = extractSomeNetconfAddress(context, InfixProp.tcp);
+        if (inetSocketAddressOptional.isPresent() == false) {
+            throw new IllegalStateException("Netconf tcp address not found." + exceptionMessageIfNotFound);
+        }
+        return inetSocketAddressOptional.get();
     }
 
+    public static Optional<InetSocketAddress> extractSSHNetconfAddress(BundleContext context) {
+        return extractSomeNetconfAddress(context, InfixProp.ssh);
+    }
+
+
     public static Optional<TLSConfiguration> extractTLSConfiguration(BundleContext context) {
         Optional<InetSocketAddress> address = extractSomeNetconfAddress(context, InfixProp.tls);
         if (address.isPresent()) {
index 0611dceb3a90472de2323ff81a4efdad3c85d9a9..2233b41a850d34e0bcd15937d5e56ae1d158280e 100644 (file)
 
                     <name>test1</name>
 
+                    <extended>
+                            1
+                    </extended>
+
+                    <extended-twice>
+                            1
+                    </extended-twice>
+
+                    <extended-enum>
+                        TWO
+                    </extended-enum>
+
                     <simple-long-2>44</simple-long-2>
                     <binaryLeaf>8</binaryLeaf>
                     <binaryLeaf>1</binaryLeaf>
@@ -85,6 +97,8 @@
                         test-impl:impl-netconf
                     </type>
                     <name>test2</name>
+                    <simple-short>4</simple-short>
+
                     <testing-dep>
                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
                         <name>ref_dep</name>
index 413b78c5d344bae7cceec2ec6752206a4cf01a46..46b833cf68cb3f4ff41442880bfe043575faf63b 100644 (file)
@@ -1,6 +1,6 @@
 <rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <no-arg xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
-        <context-instance>/modules/module[type='impl-netconf' and name='instance']</context-instance>
+        <context-instance>/modules/module[type='impl-netconf' and name='test1']</context-instance>
         <arg1>
             testarg1
         </arg1>
index cf15000b1a3473678d6f98906981d8ce68707444..3d5117e3bdf15bee2f2b51539dd5435db58874ec 100644 (file)
@@ -1,7 +1,7 @@
 <rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <noArgInner xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
         <context-instance>
-            /modules/module[name='instance2'][type='impl-netconf']/inner-running-data-additional[key='randomString_1003']
+            /modules/module[name='test1'][type='impl-netconf']/inner-running-data-additional[key='1']
         </context-instance>
     </noArgInner>
 </rpc>
index 31f417e879dd813e558e60a2a46524100027fb32..c492ee748ae73bfe8e95b9d1b5be2a3a3aee8a1a 100644 (file)
@@ -2,7 +2,7 @@
     <noArgInnerInner
             xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
         <context-instance>
-            /modules/module[type='impl-netconf'][name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017']
+            /modules/module[type='impl-netconf'][name='test2']/inner-running-data[key='2']/inner-inner-running-data[key='3']
         </context-instance>
 
         <arg1>
index af0835b5dfc7216a840557f231af108a43b2edee..4ba0349f9b7d32c2b4532f1c78eccd9d4e71fc99 100644 (file)
@@ -2,7 +2,7 @@
     <leaf-list-output
             xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
         <context-instance>
-            /modules/module[type='impl-netconf'][name='instance2']/inner-running-data[key='1015']/inner-inner-running-data[key='1017']
+            /modules/module[type='impl-netconf'][name='test1']/inner-running-data[key='0']/inner-inner-running-data[key='1']
         </context-instance>
     </leaf-list-output>
 </rpc>
index b22732e630bf0b5263d1221c9684faf2e0a14f52..ad8356431ecc4777bfee0bd1b1e7717c1a7af039 100644 (file)
@@ -26,6 +26,7 @@
         <module>config-persister-impl</module>
         <module>netconf-mapping-api</module>
         <module>netconf-client</module>
+        <module>netconf-ssh</module>
         <module>../../third-party/ganymed</module>
         <module>../../third-party/com.siemens.ct.exi</module>
     </modules>
                 <version>${netconf.version}</version>
                 <type>test-jar</type>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>netconf-ssh</artifactId>
+                <version>${netconf.version}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>netconf-mapping-api</artifactId>
index 98a6596e0e25af0eda1fbb037162d198859561bc..266b5a560a2edf01869ed66f79f709b79aca3be8 100644 (file)
@@ -41,7 +41,7 @@
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
-                        <Export-Package>ch.ethz.ssh2</Export-Package>
+                        <Export-Package>ch.ethz.ssh2.*</Export-Package>
                         <Embed-Dependency>ganymed-ssh2;scope=compile</Embed-Dependency>
                         <Embed-Transitive>true</Embed-Transitive>
                     </instructions>