Merge "Fixed potential class pool override in integration tests."
authorEd Warnicke <eaw@cisco.com>
Tue, 8 Apr 2014 16:11:16 +0000 (16:11 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 8 Apr 2014 16:11:16 +0000 (16:11 +0000)
85 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java
opendaylight/config/config-module-archetype/README.txt [new file with mode: 0644]
opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml
opendaylight/config/config-persister-directory-adapter/pom.xml [deleted file]
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java [deleted file]
opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapter.java [deleted file]
opendaylight/config/config-persister-directory-adapter/src/main/resources/footer.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/main/resources/header.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/main/resources/middle.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFile/controller.config.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedCapabilities.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedSnapshot.xml [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config1.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config2.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt [deleted file]
opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersister.java [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryStorageAdapter.java [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileType.java [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersisterTest.java [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileTypeTest.java [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/1controller.txt.config [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/2controller.xml.config [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.txt.config [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.xml.config [deleted file]
opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/unknown.config [deleted file]
opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java
opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java
opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml2 [moved from opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml with 100% similarity]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config1.xml [new file with mode: 0644]
opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config2.xml [new file with mode: 0644]
opendaylight/config/config-persister-file-adapter/pom.xml [deleted file]
opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java [deleted file]
opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java [deleted file]
opendaylight/config/pom.xml
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/assemble/bin.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/RSA.pk [deleted file]
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/md-sal/clustered-data-store/integrationtest/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/test-module/test-module
opendaylight/md-sal/samples/l2switch/implementation/pom.xml [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/L2SwitchProvider.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/addresstracker/AddressTracker.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterService.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImpl.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/inventory/InventoryService.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/packet/PacketHandler.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstra.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphService.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandler.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/util/InstanceIdentifierUtils.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImplTest.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstraTest.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandlerTest.java [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/model/pom.xml [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/model/src/main/yang/l2-address-tracker.yang [new file with mode: 0644]
opendaylight/md-sal/samples/l2switch/pom.xml [new file with mode: 0644]
opendaylight/md-sal/samples/pom.xml
opendaylight/md-sal/test/sal-rest-connector-it/pom.xml
opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-ssh/pom.xml
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java [moved from opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java with 80% similarity]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java
opendaylight/netconf/pom.xml
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java

index e7c7bbe..3690b85 100644 (file)
           <artifactId>config-persister-api</artifactId>
           <version>${config.version}</version>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>config-persister-file-adapter</artifactId>
-          <version>${config.version}</version>
-        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>config-persister-file-xml-adapter</artifactId>
           <version>${config.version}</version>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>config-persister-directory-adapter</artifactId>
-          <version>${config.version}</version>
-        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>config-persister-directory-xml-adapter</artifactId>
           <version>${config.version}</version>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>config-persister-directory-autodetect-adapter</artifactId>
-          <version>${config.version}</version>
-        </dependency>
 
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
             <artifactId>configuration</artifactId>
             <version>${configuration.version}</version>
           </dependency>
-
+            <dependency>
+                <groupId>org.bouncycastle</groupId>
+                <artifactId>bcprov-jdk15on</artifactId>
+                <version>1.50</version>
+            </dependency>
+            <dependency>
+                <groupId>org.bouncycastle</groupId>
+                <artifactId>bcpkix-jdk15on</artifactId>
+                <version>1.50</version>
+            </dependency>
     </dependencies>
   </dependencyManagement>
 
index e90af73..5e55cdd 100644 (file)
@@ -89,11 +89,23 @@ public abstract class AbstractDispatcher<S extends ProtocolSession<?>, L extends
         });
         b.childOption(ChannelOption.SO_KEEPALIVE, true);
 
+        customizeBootstrap(b);
+
         // Bind and start to accept incoming connections.
         final ChannelFuture f = b.bind(address);
         LOG.debug("Initiated server {} at {}.", f, address);
         return f;
+    }
 
+    /**
+     * Customize a server bootstrap before the server is created. This allows
+     * subclasses to assign non-default server options before the server is
+     * created.
+     *
+     * @param b Server bootstrap
+     */
+    protected void customizeBootstrap(final ServerBootstrap b) {
+        // The default is a no-op
     }
 
     /**
@@ -116,11 +128,25 @@ public abstract class AbstractDispatcher<S extends ProtocolSession<?>, L extends
                         initializer.initializeChannel(ch, p);
                     }
                 });
+
+        customizeBootstrap(b);
+
         p.connect();
         LOG.debug("Client created.");
         return p;
     }
 
+    /**
+     * Customize a client bootstrap before the connection is attempted. This
+     * allows subclasses to assign non-default options before the client is
+     * created.
+     *
+     * @param b Client bootstrap
+     */
+    protected void customizeBootstrap(final Bootstrap b) {
+        // The default is a no-op
+    }
+
     /**
      * Creates a client.
      *
@@ -138,7 +164,6 @@ public abstract class AbstractDispatcher<S extends ProtocolSession<?>, L extends
         p.connect();
 
         return p;
-
     }
 
     /**
diff --git a/opendaylight/config/config-module-archetype/README.txt b/opendaylight/config/config-module-archetype/README.txt
new file mode 100644 (file)
index 0000000..8b1f29b
--- /dev/null
@@ -0,0 +1,12 @@
+Use
+GROUP_ID=com.mycompany.app
+ARTIFACT_ID=my-app
+mvn archetype:generate -DgroupId=$GROUP_ID -DartifactId=$ARTIFACT_ID \
+ -DarchetypeArtifactId=config-module-archetype -DarchetypeGroupId=org.opendaylight.controller  \
+ -DarchetypeVersion=0.2.5-SNAPSHOT
+
+Module name and prefix define yang module name and its java name prefix.
+For example when creating thread factory wrapper, yang name might be
+thread-factory
+and java prefix
+ThreadFactory
\ No newline at end of file
index fc30b4d..f7b8729 100644 (file)
@@ -15,7 +15,7 @@
             <defaultValue>2013-04-05</defaultValue>
         </requiredProperty>
         <requiredProperty key="config-api-version">
-            <defaultValue>0.2.4-SNAPSHOT</defaultValue>
+            <defaultValue>0.2.5-SNAPSHOT</defaultValue>
         </requiredProperty>
         <requiredProperty key="yang-maven-plugin-version">
             <defaultValue>0.6.2-SNAPSHOT</defaultValue>
index d1c371d..21b1a55 100644 (file)
@@ -9,8 +9,13 @@
 
     <properties>
         <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+        <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
         <config.version>${config-api-version}</config.version>
+        <yangtools.version>${yang-maven-plugin-version}</yangtools.version>
         <maven.bundle.version>${maven-bundle-plugin-version}</maven.bundle.version>
+        <java.version.source>1.7</java.version.source>
+        <java.version.target>1.7</java.version.target>
+        <maven.compile.plugin.version>2.5.1</maven.compile.plugin.version>
     </properties>
 
     <dependencies>
@@ -26,7 +31,7 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yang-maven-plugin-version}</version>
+                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <id>config</id>
                                         </namespaceToPackage1>
                                     </additionalConfiguration>
                                 </generator>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        ${salGeneratorPath}
+                                    </outputBaseDir>
+                                </generator>
                             </codeGenerators>
                             <inspectDependencies>true</inspectDependencies>
                         </configuration>
                         <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.version}</version>
+                    </dependency>
                 </dependencies>
             </plugin>
 
                 <configuration>
                     <instructions>
                         <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
-                        <Export-Package>
-                            ${yang-namespace-mapping-to}.${module-name},
-                        </Export-Package>
-                        <Import-Package>
-                            *
-                        </Import-Package>
                     </instructions>
                 </configuration>
             </plugin>
 
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven.compile.plugin.version}</version>
+                <configuration>
+                    <source>${java.version.source}</source>
+                    <target>${java.version.target}</target>
+                    <testSource>${java.version.source}</testSource>
+                    <testTarget>${java.version.target}</testTarget>
+                </configuration>
+            </plugin>
 
         </plugins>
     </build>
diff --git a/opendaylight/config/config-persister-directory-adapter/pom.xml b/opendaylight/config/config-persister-directory-adapter/pom.xml
deleted file mode 100644 (file)
index 86b8c4d..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?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.5-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.yangtools</groupId>
-            <artifactId>mockito-configuration</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>config-persister-api</artifactId>
-            <type>test-jar</type>
-            <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
deleted file mode 100644 (file)
index eb8ef8c..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.persist.storage.directory;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.Files;
-import org.apache.commons.io.IOUtils;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-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;
-
-    public 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 static final String header, middle, footer;
-
-    static {
-        header = readResource("header.txt");
-        middle = readResource("middle.txt");
-        footer = readResource("footer.txt");
-    }
-
-    public DirectoryPersister(File storage) {
-        checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
-        this.storage = storage;
-    }
-
-    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 List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
-        File[] filesArray = storage.listFiles();
-        if (filesArray == null || filesArray.length == 0) {
-            return Collections.emptyList();
-        }
-        List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
-        Collections.sort(sortedFiles);
-        // combine all found files
-        logger.debug("Reading files in following order: {}", sortedFiles);
-
-        List<ConfigSnapshotHolder> result = new ArrayList<>();
-        for (File file : sortedFiles) {
-            logger.trace("Adding file '{}' to combined result", file);
-
-            ConfigSnapshotHolder configSnapshotHolder = loadLastConfig(file);
-            result.add(configSnapshotHolder);
-        }
-        return result;
-    }
-
-    public static ConfigSnapshotHolder loadLastConfig(File file) throws IOException {
-        final MyLineProcessor lineProcessor = new MyLineProcessor(file.getAbsolutePath());
-        Files.readLines(file, ENCODING, lineProcessor);
-        return lineProcessor.getConfigSnapshotHolder(header, middle, footer);
-    }
-
-
-    @Override
-    public void close() {
-
-    }
-
-    @Override
-    public String toString() {
-        return "FileStorageAdapter [storage=" + storage + "]";
-    }
-}
-
-class MyLineProcessor implements com.google.common.io.LineProcessor<String> {
-    private final String fileNameForReporting;
-
-    private boolean inModules, inServices, inCapabilities;
-    private final StringBuffer modulesBuffer = new StringBuffer(), servicesBuilder = new StringBuffer();
-    private final SortedSet<String> caps = new TreeSet<>();
-
-    MyLineProcessor(String fileNameForReporting) {
-        this.fileNameForReporting = fileNameForReporting;
-    }
-
-    @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;
-    }
-
-    private void checkFileConsistency(){
-        checkState(inCapabilities, "File %s is missing delimiters in this order: %s", fileNameForReporting,
-                Arrays.asList(DirectoryPersister.MODULES_START,
-                        DirectoryPersister.SERVICES_START,
-                        DirectoryPersister.CAPABILITIES_START));
-    }
-
-    String getModules() {
-        checkFileConsistency();
-        return modulesBuffer.toString();
-    }
-
-    String getServices() {
-        checkFileConsistency();
-        return servicesBuilder.toString();
-    }
-
-    SortedSet<String> getCapabilities() {
-        checkFileConsistency();
-        return caps;
-    }
-
-    ConfigSnapshotHolder getConfigSnapshotHolder(String header, String middle, String footer) {
-        String combinedSnapshot = header + getModules() + middle + getServices() + footer;
-        ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, getCapabilities(), fileNameForReporting);
-        return result;
-    }
-
-}
-
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
deleted file mode 100644 (file)
index 69c8fba..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.config.persist.storage.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
deleted file mode 100644 (file)
index d4dcc62..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-    </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
deleted file mode 100644 (file)
index 90ed41c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<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
deleted file mode 100644 (file)
index f728cfd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-    </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
deleted file mode 100644 (file)
index 278d0d2..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.config.persist.storage.directory;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import org.apache.commons.io.IOUtils;
-import org.junit.Test;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.test.PropertiesProviderTest;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-public class DirectoryStorageAdapterTest {
-    Persister tested;
-
-    private Persister instantiatePersisterFromAdapter(File file){
-        PropertiesProviderTest pp = new PropertiesProviderTest();
-        pp.addProperty("directoryStorage",file.getPath());
-        DirectoryStorageAdapter dsa = new DirectoryStorageAdapter();
-        return dsa.instantiate(pp);
-    }
-    @Test
-    public void testEmptyDirectory() throws Exception {
-        File folder = new File("target/emptyFolder");
-        folder.mkdir();
-
-        tested =  instantiatePersisterFromAdapter(folder);
-        assertEquals(Collections.<ConfigSnapshotHolder>emptyList(), tested.loadLastConfigs());
-
-        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 = instantiatePersisterFromAdapter(folder);
-
-        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
-        assertEquals(1, results.size());
-        ConfigSnapshotHolder result = results.get(0);
-        assertSnapshot(result, "oneFileExpected");
-    }
-
-
-    @Test
-    public void testTwoFiles() throws Exception {
-        File folder = getFolder("twoFiles");
-        tested = instantiatePersisterFromAdapter(folder);
-
-        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
-        assertEquals(2, results.size());
-        assertSnapshot(results.get(0), "twoFilesExpected1");
-        assertSnapshot(results.get(1), "twoFilesExpected2");
-    }
-
-    private void assertSnapshot(ConfigSnapshotHolder result, String directory) throws Exception {
-        SortedSet<String> expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/" + directory + "/expectedCapabilities.txt")));
-        String expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/" + directory + "/expectedSnapshot.xml"));
-        expectedSnapshot = expectedSnapshot.replaceAll("\r","");
-        String _snapshot = result.getConfigSnapshot();
-        _snapshot = _snapshot.replaceAll("\r","");
-        assertEquals(expectedCapabilities, result.getCapabilities());
-        assertEquals(expectedSnapshot, _snapshot);
-    }
-
-}
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
deleted file mode 100644 (file)
index 99b4cb9..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-//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/oneFileExpected/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedCapabilities.txt
deleted file mode 100644 (file)
index 84c85b7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-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/oneFileExpected/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedSnapshot.xml
deleted file mode 100644 (file)
index a6a57d7..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-<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/twoFiles/controller.config1.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config1.txt
deleted file mode 100644 (file)
index 6ae48fb..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-//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
deleted file mode 100644 (file)
index ad9138f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-//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
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt
deleted file mode 100644 (file)
index ef35fdd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml
deleted file mode 100644 (file)
index 2b1d06e..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
-    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-        <module>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
-            <name>yang-schema-service</name>
-        </module>
-        <module>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
-            <name>hash-map-data-store</name>
-        </module>
-        <module>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
-            <name>dom-broker</name>
-            <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
-                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
-                <name>ref_hash-map-data-store</name>
-            </data-store>
-        </module>
-        <module>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
-            <name>binding-broker-impl</name>
-            <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
-                <name>ref_binding-notification-broker</name>
-            </notification-service>
-            <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
-                <name>ref_binding-data-broker</name>
-            </data-broker>
-        </module>
-        <module>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
-            <name>runtime-mapping-singleton</name>
-        </module>
-        <module>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
-            <name>binding-notification-broker</name>
-        </module>
-    </modules>
-    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-        <service>
-            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
-            <instance>
-                <name>ref_yang-schema-service</name>
-                <provider>/config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']</provider>
-            </instance>
-        </service>
-        <service>
-            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
-            <instance>
-                <name>ref_binding-notification-broker</name>
-                <provider>/config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']</provider>
-            </instance>
-        </service>
-        <service>
-            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
-            <instance>
-                <name>ref_hash-map-data-store</name>
-                <provider>/config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']</provider>
-            </instance>
-        </service>
-        <service>
-            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
-            <instance>
-                <name>ref_binding-broker-impl</name>
-                <provider>/config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']</provider>
-            </instance>
-        </service>
-        <service>
-            <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
-            <instance>
-                <name>ref_runtime-mapping-singleton</name>
-                <provider>/config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']</provider>
-            </instance>
-        </service>
-        <service>
-            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
-            <instance>
-                <name>ref_dom-broker</name>
-                <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']</provider>
-            </instance>
-        </service>
-    </services>
-</data>
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt
deleted file mode 100644 (file)
index 9924111..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
-urn:ietf:params:netconf:capability:candidate:1.0
-urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04
-urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12
-urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
-urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24
-urn:ietf:params:netconf:capability:rollback-on-error:1.0
-urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24
-urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16
-urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09
-urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16
-urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
-urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19
diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml
deleted file mode 100644 (file)
index 887cb2c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
-    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-        <module>
-            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
-            <name>binding-data-broker</name>
-            <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
-                <name>ref_dom-broker</name>
-            </dom-broker>
-            <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
-                <name>ref_runtime-mapping-singleton</name>
-            </mapping-service>
-        </module>
-    </modules>
-    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-        <service>
-            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
-            <instance>
-                <name>ref_binding-data-broker</name>
-                <provider>/config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']</provider>
-            </instance>
-        </service>
-    </services>
-</data>
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml b/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml
deleted file mode 100644 (file)
index 5e556c0..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?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.5-SNAPSHOT</version>
-        <relativePath>..</relativePath>
-    </parent>
-    <artifactId>config-persister-directory-autodetect-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.opendaylight.controller</groupId>
-            <artifactId>config-persister-directory-adapter</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-directory-xml-adapter</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.yangtools</groupId>
-            <artifactId>mockito-configuration</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>config-persister-api</artifactId>
-            <type>test-jar</type>
-            <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,
-                            com.google.common.collect,
-                            javax.xml.bind,
-                            javax.xml.bind.annotation,
-                            javax.xml.transform,
-                            javax.xml.transform.stream,
-                            org.eclipse.persistence.jaxb,
-                            org.apache.commons.lang3
-                        </Import-Package>
-                        <Private-Package>
-                            org.opendaylight.controller.config.persist.storage.file.xml.model,
-                            org.opendaylight.controller.config.persist.storage.directory,
-                            org.opendaylight.controller.config.persist.storage.directory.xml,
-                        </Private-Package>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersister.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersister.java
deleted file mode 100644 (file)
index 2028d62..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.persist.storage.directory.autodetect;
-
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.storage.directory.DirectoryPersister;
-import org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryPersister;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.xml.bind.JAXBException;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-public class AutodetectDirectoryPersister implements Persister {
-    private static final Logger logger = LoggerFactory.getLogger(AutodetectDirectoryPersister.class);
-
-    private final File storage;
-
-    public AutodetectDirectoryPersister(File storage) {
-        checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
-        this.storage = storage;
-    }
-
-    @Override
-    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
-        throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
-    }
-
-    @Override
-    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
-        File[] filesArray = storage.listFiles();
-        if (filesArray == null || filesArray.length == 0) {
-            return Collections.emptyList();
-        }
-        List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
-        Collections.sort(sortedFiles);
-
-        // combine all found files
-        logger.debug("Reading files in following order: {}", sortedFiles);
-
-        List<ConfigSnapshotHolder> result = new ArrayList<>();
-        for (File file : sortedFiles) {
-            logger.trace("Adding file '{}' to combined result", file);
-
-            FileType fileType = FileType.getFileType(file);
-            logger.trace("File '{}' detected as {} storage", file, fileType);
-
-            ConfigSnapshotHolder snapshot = loadLastConfig(file, fileType);
-            result.add(snapshot);
-        }
-        return result;
-    }
-
-    private ConfigSnapshotHolder loadLastConfig(File file, FileType fileType) throws IOException {
-        switch (fileType) {
-        case plaintext:
-            logger.warn("Plaintext configuration files are deprecated, and will not be supported in future versions. " +
-                    "Use xml files instead");
-            return DirectoryPersister.loadLastConfig(file);
-        case xml:
-            try {
-                return XmlDirectoryPersister.loadLastConfig(file);
-            } catch (JAXBException e) {
-                logger.warn("Unable to restore configuration snapshot from {}", file, e);
-                throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e);
-            }
-        default:
-            throw new IllegalStateException("Unknown storage type " + fileType);
-        }
-    }
-
-    @Override
-    public void close() {
-
-    }
-
-    @Override
-    public String toString() {
-        final StringBuffer sb = new StringBuffer("AutodetectDirectoryPersister{");
-        sb.append("storage=").append(storage);
-        sb.append('}');
-        return sb.toString();
-    }
-}
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryStorageAdapter.java
deleted file mode 100644 (file)
index f856ddd..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.config.persist.storage.directory.autodetect;
-
-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 AutodetectDirectoryStorageAdapter implements StorageAdapter {
-    private static final Logger logger = LoggerFactory.getLogger(AutodetectDirectoryStorageAdapter.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 AutodetectDirectoryPersister(storage);
-    }
-
-}
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileType.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileType.java
deleted file mode 100644 (file)
index 779a887..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.persist.storage.directory.autodetect;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Charsets;
-import com.google.common.io.Files;
-import org.apache.commons.lang3.StringUtils;
-import org.opendaylight.controller.config.persist.storage.directory.DirectoryPersister;
-import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-
-enum FileType {
-
-    plaintext, xml;
-
-    public static final String XML_STORAGE_FIRST_LINE = "<" + ConfigSnapshot.SNAPSHOT_ROOT_ELEMENT_NAME + ">";
-    private static final String XML_FILE_DEFINITION_LINE = "<?xml";
-
-    static FileType getFileType(File file) {
-        String firstLine = readFirstLine(file);
-        if(isPlaintextStorage(firstLine)) {
-            return plaintext;
-        } else if(isXmlStorage(firstLine))
-            return xml;
-
-        throw new IllegalArgumentException("File " + file + " is not of permitted storage type: " + Arrays.toString(FileType.values()));
-    }
-
-    private static boolean isXmlStorage(String firstLine) {
-        boolean isXml = false;
-        isXml |= firstLine.startsWith(XML_STORAGE_FIRST_LINE);
-        isXml |= firstLine.startsWith(XML_FILE_DEFINITION_LINE);
-        return isXml;
-    }
-
-    private static boolean isPlaintextStorage(String firstLine) {
-        return firstLine.startsWith(DirectoryPersister.MODULES_START);
-
-    }
-
-    @VisibleForTesting
-    static String readFirstLine(File file) {
-        FirstLineReadingProcessor callback = new FirstLineReadingProcessor();
-        try {
-            return Files.readLines(file, Charsets.UTF_8, callback);
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Unable to detect file type of file " + file, e);
-        }
-    }
-
-
-    private static class FirstLineReadingProcessor implements com.google.common.io.LineProcessor<String> {
-        private String firstNonBlankLine;
-
-        @Override
-        public boolean processLine(String line) throws IOException {
-            if(isEmptyLine(line)) {
-                return true;
-            } else {
-                firstNonBlankLine = line.trim();
-                return false;
-            }
-        }
-
-        private boolean isEmptyLine(String line) {
-            return StringUtils.isBlank(line);
-        }
-
-        @Override
-        public String getResult() {
-            return firstNonBlankLine;
-        }
-    }
-}
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersisterTest.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersisterTest.java
deleted file mode 100644 (file)
index bcade93..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.persist.storage.directory.autodetect;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import junit.framework.Assert;
-import org.junit.Test;
-import org.junit.matchers.JUnitMatchers;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.test.PropertiesProviderTest;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-public class AutodetectDirectoryPersisterTest {
-
-    @Test
-    public void testCombined() throws Exception {
-        File resourcePath = FileTypeTest.getResourceAsFile("/combined/1controller.txt.config");
-        File parentFile = resourcePath.getParentFile();
-
-        AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter();
-
-        PropertiesProviderTest pp = new PropertiesProviderTest();
-        pp.addProperty("directoryStorage",parentFile.getPath());
-        AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp);
-        List<ConfigSnapshotHolder> configs = persister.loadLastConfigs();
-
-        Assert.assertEquals(2, configs.size());
-        String snapFromTxt = configs.get(0).getConfigSnapshot();
-        org.junit.Assert.assertThat(snapFromTxt, JUnitMatchers.containsString("<config>txt</config>"));
-        org.junit.Assert.assertThat(snapFromTxt, JUnitMatchers.containsString("<service>txt</service>"));
-
-        String snapFromXml = configs.get(1).getConfigSnapshot();
-        org.junit.Assert.assertThat(snapFromXml, JUnitMatchers.containsString("<config>xml</config>"));
-
-        Assert.assertEquals(configs.get(0).getCapabilities(), configs.get(1).getCapabilities());
-    }
-
-    @Test
-    public void testInvalidXml() throws Exception {
-        File resourcePath = FileTypeTest.getResourceAsFile("/bad_controller.xml.config");
-        File parentFile = resourcePath.getParentFile();
-
-        AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter();
-
-        PropertiesProviderTest pp = new PropertiesProviderTest();
-        pp.addProperty("directoryStorage",parentFile.getPath());
-        AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp);
-        try {
-            List<ConfigSnapshotHolder> configs = persister.loadLastConfigs();
-            fail("An exception of type " + IllegalStateException.class + " was expected");
-        } catch (IllegalStateException ise){
-            String message = ise.getMessage();
-            assertThat(message, JUnitMatchers.containsString("Unable to restore configuration snapshot from "));
-        }
-
-    }
-
-    @Test
-    public void testPersistConfig() throws Exception {
-        File resourcePath = FileTypeTest.getResourceAsFile("/combined/1controller.txt.config");
-        File parentFile = resourcePath.getParentFile();
-
-        AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter();
-
-        PropertiesProviderTest pp = new PropertiesProviderTest();
-        pp.addProperty("directoryStorage",parentFile.getPath());
-        AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp);
-        List<ConfigSnapshotHolder> configs = null;
-        try {
-            configs = persister.loadLastConfigs();
-        } catch (IOException e) {
-            fail("An exception of type " + UnsupportedOperationException.class + " was expected");
-        }
-        Assert.assertEquals(2, configs.size());
-        try {
-            persister.persistConfig(configs.get(0));
-        } catch (UnsupportedOperationException uoe){
-            String message = uoe.getMessage();
-            assertThat(message,JUnitMatchers.containsString("This adapter is read only. Please set readonly=true on class"));
-        }
-    }
-
-}
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileTypeTest.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileTypeTest.java
deleted file mode 100644 (file)
index bbc272d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.persist.storage.directory.autodetect;
-
-import junit.framework.Assert;
-import org.junit.Test;
-import org.junit.matchers.JUnitMatchers;
-
-import java.io.File;
-
-public class FileTypeTest {
-
-    @Test
-    public void testPlaintext() throws Exception {
-        File file = getResourceAsFile("/test.txt.config");
-
-        FileType type = FileType.getFileType(file);
-        Assert.assertEquals(FileType.plaintext, type);
-
-    }
-
-    @Test
-    public void testXml() throws Exception {
-        File file = getResourceAsFile("/test.xml.config");
-
-        FileType type = FileType.getFileType(file);
-        Assert.assertEquals(FileType.xml, type);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testUnknown() throws Exception {
-        File file = getResourceAsFile("/unknown.config");
-
-        try {
-            FileType.getFileType(file);
-        } catch (IllegalArgumentException e) {
-            org.junit.Assert.assertThat(e.getMessage(), JUnitMatchers.containsString("File " + file + " is not of permitted storage type"));
-            throw e;
-        }
-    }
-
-    static File getResourceAsFile(String resource) {
-        String f = FileTypeTest.class.getResource(resource).getFile();
-        return new File(f);
-    }
-
-}
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config
deleted file mode 100644 (file)
index 3f6a337..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<snapshot>
-    <required-capabilities>
-        <capability
-        <capability>cap2</capability>
-        <capability>capa a</capability>
-    </required-capabilities>
-    <configuration>
-        <config>xml</config>
-    </configuration>
-</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/1controller.txt.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/1controller.txt.config
deleted file mode 100644 (file)
index f72cd1c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-//MODULES START
-        <config>txt</config>
-//SERVICES START
-        <service>txt</service>
-//CAPABILITIES START
-cap1&rev
-cap2
-capa a
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/2controller.xml.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/2controller.xml.config
deleted file mode 100644 (file)
index 988f866..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<snapshot>
-    <required-capabilities>
-        <capability>cap1&amp;rev</capability>
-        <capability>cap2</capability>
-        <capability>capa a</capability>
-    </required-capabilities>
-    <configuration>
-        <config>xml</config>
-    </configuration>
-</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.txt.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.txt.config
deleted file mode 100644 (file)
index edf37ca..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-//MODULES START
-configuration
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.xml.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.xml.config
deleted file mode 100644 (file)
index fe94299..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-
-<snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/unknown.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/unknown.config
deleted file mode 100644 (file)
index c4218c8..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-unknown
-file type
\ No newline at end of file
index 0ca47ed..7f8ebd7 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.config.persist.storage.directory.xml;
 
+import com.google.common.base.Optional;
+import com.google.common.io.Files;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
@@ -17,11 +19,13 @@ import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
 import java.io.File;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.SortedSet;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -30,10 +34,26 @@ public class XmlDirectoryPersister implements Persister {
     private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryPersister.class);
 
     private final File storage;
+    private final Optional<FilenameFilter> extensionsFilter;
 
+    /**
+     * Creates XmlDirectoryPersister that picks up all files in specified folder
+     */
     public XmlDirectoryPersister(File storage) {
+        this(storage, Optional.<FilenameFilter>absent());
+    }
+
+    /**
+     * Creates XmlDirectoryPersister that picks up files only with specified file extension
+     */
+    public XmlDirectoryPersister(File storage, Set<String> fileExtensions) {
+        this(storage, Optional.of(getFilter(fileExtensions)));
+    }
+
+    private XmlDirectoryPersister(File storage, Optional<FilenameFilter> extensionsFilter) {
         checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
         this.storage = storage;
+        this.extensionsFilter = extensionsFilter;
     }
 
     @Override
@@ -43,7 +63,7 @@ public class XmlDirectoryPersister implements Persister {
 
     @Override
     public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
-        File[] filesArray = storage.listFiles();
+        File[] filesArray = extensionsFilter.isPresent() ? storage.listFiles(extensionsFilter.get()) : storage.listFiles();
         if (filesArray == null || filesArray.length == 0) {
             return Collections.emptyList();
         }
@@ -55,19 +75,30 @@ public class XmlDirectoryPersister implements Persister {
         List<ConfigSnapshotHolder> result = new ArrayList<>();
         for (File file : sortedFiles) {
             logger.trace("Adding file '{}' to combined result", file);
-            ConfigSnapshotHolder h = fromXmlSnapshot(file);
-            result.add(h);
+            Optional<ConfigSnapshotHolder> h = fromXmlSnapshot(file);
+            // Ignore non valid snapshot
+            if(h.isPresent() == false) {
+                continue;
+            }
+
+            result.add(h.get());
         }
         return result;
     }
 
-    private ConfigSnapshotHolder fromXmlSnapshot(File file) {
+    private Optional<ConfigSnapshotHolder> fromXmlSnapshot(File file) {
         try {
-            return loadLastConfig(file);
+            return Optional.of(loadLastConfig(file));
         } catch (JAXBException e) {
-            logger.warn("Unable to restore configuration snapshot from {}", file, e);
-            throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e);
+            // In case of parse error, issue a warning, ignore and continue
+            logger.warn(
+                    "Unable to parse configuration snapshot from {}. Initial config from {} will be IGNORED in this run. " +
+                    "Note that subsequent config files may fail due to this problem. " +
+                    "Xml markup in this file needs to be fixed, for detailed information see enclosed exception.",
+                    file, file, e);
         }
+
+        return Optional.absent();
     }
 
     public static ConfigSnapshotHolder loadLastConfig(File file) throws JAXBException {
@@ -96,6 +127,17 @@ public class XmlDirectoryPersister implements Persister {
         };
     }
 
+    private static FilenameFilter getFilter(final Set<String>fileExtensions) {
+        checkArgument(fileExtensions.isEmpty() == false, "No file extension provided", fileExtensions);
+
+        return new FilenameFilter() {
+            @Override
+            public boolean accept(File dir, String name) {
+                String ext = Files.getFileExtension(name);
+                return fileExtensions.contains(ext);
+            }
+        };
+    }
 
     @Override
     public void close() {
index ab6fb15..40f8c28 100644 (file)
@@ -9,6 +9,8 @@
 package org.opendaylight.controller.config.persist.storage.directory.xml;
 
 import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Sets;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
 import org.opendaylight.controller.config.persist.api.StorageAdapter;
@@ -16,6 +18,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
+import java.util.Set;
 
 /**
  * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and
@@ -25,6 +28,8 @@ public class XmlDirectoryStorageAdapter implements StorageAdapter {
     private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryStorageAdapter.class);
 
     public static final String DIRECTORY_STORAGE_PROP = "directoryStorage";
+    public static final String INCLUDE_EXT_PROP = "includeExtensions";
+    private static final char EXTENSIONS_SEPARATOR = ',';
 
 
     @Override
@@ -32,8 +37,21 @@ public class XmlDirectoryStorageAdapter implements StorageAdapter {
         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 XmlDirectoryPersister(storage);
+        String fileExtensions = propertiesProvider.getProperty(INCLUDE_EXT_PROP);
+
+        logger.debug("Using storage: {}", storage);
+
+        if(fileExtensions != null) {
+            logger.debug("Using extensions: {}", fileExtensions);
+            return new XmlDirectoryPersister(storage, splitExtensions(fileExtensions));
+        } else {
+            return new XmlDirectoryPersister(storage);
+        }
+    }
+
+    private Set<String> splitExtensions(String fileExtensions) {
+        return Sets.newHashSet(Splitter.on(EXTENSIONS_SEPARATOR).trimResults().omitEmptyStrings()
+                .split(fileExtensions));
     }
 
 }
index 8e34bc7..da442ef 100644 (file)
@@ -12,6 +12,8 @@ import java.io.File;
 import java.util.Collections;
 import java.util.List;
 import java.util.SortedSet;
+
+import com.google.common.base.Optional;
 import org.junit.Test;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
@@ -26,13 +28,21 @@ public class DirectoryStorageAdapterTest {
     Persister tested;
     Logger logger = LoggerFactory.getLogger(DirectoryStorageAdapterTest.class.toString());
 
-    private Persister instantiatePersisterFromAdapter(File file){
+    private Persister instantiatePersisterFromAdapter(File file, Optional<String> extensions){
         PropertiesProviderTest pp = new PropertiesProviderTest();
-        pp.addProperty("directoryStorage",file.getPath());
+        pp.addProperty(XmlDirectoryStorageAdapter.DIRECTORY_STORAGE_PROP,file.getPath());
+        if(extensions.isPresent()) {
+            pp.addProperty(XmlDirectoryStorageAdapter.INCLUDE_EXT_PROP, extensions.get());
+        }
+
         XmlDirectoryStorageAdapter dsa = new XmlDirectoryStorageAdapter();
         return dsa.instantiate(pp);
     }
 
+    private Persister instantiatePersisterFromAdapter(File file){
+        return instantiatePersisterFromAdapter(file, Optional.<String>absent());
+    }
+
     @Test
     public void testEmptyDirectory() throws Exception {
         File folder = new File("target/emptyFolder");
@@ -69,15 +79,22 @@ public class DirectoryStorageAdapterTest {
     @Test
     public void testOneFile() throws Exception {
         File folder = getFolder("oneFile");
-        tested = instantiatePersisterFromAdapter(folder);
+        tested = instantiatePersisterFromAdapter(folder, Optional.of("xml"));
 
-        logger.info("Testing : "+tested.toString());
+        logger.info("Testing : " + tested.toString());
         List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
         assertEquals(1, results.size());
         ConfigSnapshotHolder result = results.get(0);
         assertResult(result, "<config>1</config>", "cap1&rev", "cap2", "capa a");
     }
 
+    @Test
+    public void testOneFileWrongExtension() throws Exception {
+        File folder = getFolder("oneFile");
+        tested = instantiatePersisterFromAdapter(folder, Optional.of("aa, bb"));
+        logger.info("Testing : " + tested.toString());
+    }
+
     private void assertResult(ConfigSnapshotHolder result, String s, String... caps) {
         assertEquals(s, result.getConfigSnapshot().replaceAll("\\s", ""));
         int i = 0;
@@ -87,16 +104,45 @@ public class DirectoryStorageAdapterTest {
     }
 
     @Test
-    public void testTwoFiles() throws Exception {
+    public void testTwoFilesAllExtensions() throws Exception {
         File folder = getFolder("twoFiles");
         tested = instantiatePersisterFromAdapter(folder);
-        logger.info("Testing : "+tested.toString());
+        logger.info("Testing : " + tested.toString());
         List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
         assertEquals(2, results.size());
 
         assertResult(results.get(0), "<config>1</config>", "cap1-a", "cap2-a", "capa a-a");
         assertResult(results.get(1), "<config>2</config>", "cap1-b", "cap2-b", "capa a-b");
+    }
+
+    @Test
+    public void testTwoFilesTwoExtensions() throws Exception {
+        File folder = getFolder("twoFiles");
+        tested = instantiatePersisterFromAdapter(folder, Optional.of("xml, xml2"));
+        logger.info("Testing : " + tested.toString());
+        assertEquals(2, tested.loadLastConfigs().size());
+    }
+
+    @Test
+    public void testTwoFilesOnlyOneExtension() throws Exception {
+        File folder = getFolder("twoFiles");
+        tested = instantiatePersisterFromAdapter(folder, Optional.of("xml"));
+        logger.info("Testing : " + tested.toString());
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(1, results.size());
 
+        assertResult(results.get(0), "<config>1</config>", "cap1-a", "cap2-a", "capa a-a");
+    }
+
+    @Test
+    public void testTwoFilesOneInvalid() throws Exception {
+        File folder = getFolder("twoFiles_corrupt");
+        tested = instantiatePersisterFromAdapter(folder, Optional.of("xml"));
+        logger.info("Testing : " + tested.toString());
+        List<ConfigSnapshotHolder> results = tested.loadLastConfigs();
+        assertEquals(1, results.size());
+
+        assertResult(results.get(0), "<config>1</config>", "cap1-a", "cap2-a", "capa a-a");
     }
 
 }
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config1.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config1.xml
new file mode 100644 (file)
index 0000000..28f112e
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshot>
+    <required-capabilities>
+        <capability>cap1-a</capability>
+        <capability>cap2-a</capability>
+        <capability>capa a-a</capability>
+    </required-capabilities>
+    <configuration>
+        <config>1</config>
+    </configuration>
+</snapshot>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config2.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config2.xml
new file mode 100644 (file)
index 0000000..ed781d5
--- /dev/null
@@ -0,0 +1,10 @@
+<snapshotInvalid>
+    <required-capabilities>
+        <capability>cap1-b</capability>
+        <capability>cap2-b</capability>
+        <capability>capa a-b</capability>
+    </required-capabilities>
+    <configuration>
+        <config>2</config>
+    </configuration>
+</snapshotInvalid>
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-file-adapter/pom.xml b/opendaylight/config/config-persister-file-adapter/pom.xml
deleted file mode 100644 (file)
index a8ea93e..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<?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.5-SNAPSHOT</version>
-        <relativePath>..</relativePath>
-    </parent>
-    <artifactId>config-persister-file-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>
-
-        <!-- test dependencies -->
-        <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>mockito-configuration</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>config-persister-api</artifactId>
-            <type>test-jar</type>
-            <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>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-</project>
diff --git a/opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java b/opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java
deleted file mode 100644 (file)
index 1b9948b..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.config.persist.storage.file;
-
-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.io.Files;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import org.apache.commons.lang3.StringUtils;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-import org.opendaylight.controller.config.persist.api.StorageAdapter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * StorageAdapter that stores configuration in a plain file.
- */
-public class FileStorageAdapter implements StorageAdapter, Persister {
-    private static final Logger logger = LoggerFactory.getLogger(FileStorageAdapter.class);
-
-
-    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);
-
-    private static final String SEPARATOR_M_PURE = "//END OF SNAPSHOT";
-    private static final String SEPARATOR_M = newLine(SEPARATOR_M_PURE);
-
-    private static final String SEPARATOR_S = newLine("//START OF CONFIG");
-
-    private static final String SEPARATOR_SL_PURE = "//START OF CONFIG-LAST";
-    private static final String SEPARATOR_SL = newLine(SEPARATOR_SL_PURE);
-
-    private static Integer numberOfStoredBackups;
-    private File storage;
-
-    @Override
-    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();
-        if (parentFile.exists() == false) {
-            logger.debug("Creating parent folders {}", parentFile);
-            parentFile.mkdirs();
-        }
-        if (storage.exists() == false) {
-            logger.debug("Storage file does not exist, creating empty file");
-            try {
-                boolean result = storage.createNewFile();
-                if (result == false)
-                    throw new RuntimeException("Unable to create storage file " + storage);
-            } catch (IOException e) {
-                throw new RuntimeException("Unable to create storage file " + storage, e);
-            }
-        }
-        if (numberOfStoredBackups == 0) {
-            throw new RuntimeException(NUMBER_OF_BACKUPS
-                    + " property should be either set to positive value, or ommited. Can not be set to 0.");
-        }
-        setFileStorage(storage);
-        return this;
-    }
-
-    @VisibleForTesting
-    void setFileStorage(File storage) {
-        this.storage = storage;
-    }
-
-    @VisibleForTesting
-    void setNumberOfBackups(Integer numberOfBackups) {
-        numberOfStoredBackups = numberOfBackups;
-    }
-
-    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 = propertiesProvider.getProperty(NUMBER_OF_BACKUPS);
-        if (numberOfBAckupsAsString != null) {
-            numberOfStoredBackups = Integer.valueOf(numberOfBAckupsAsString);
-        } else {
-            numberOfStoredBackups = Integer.MAX_VALUE;
-        }
-        logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
-        return result;
-    }
-
-    private static String newLine(String string) {
-        return string + "\n";
-    }
-
-    @Override
-    public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
-        Preconditions.checkNotNull(storage, "Storage file is null");
-
-        String content = Files.toString(storage, ENCODING);
-        if (numberOfStoredBackups == Integer.MAX_VALUE) {
-            resetLastConfig(content);
-            persistLastConfig(holder);
-        } else {
-            if (numberOfStoredBackups == 1) {
-                Files.write("", storage, ENCODING);
-                persistLastConfig(holder);
-            } else {
-                int count = StringUtils.countMatches(content, SEPARATOR_S);
-                if ((count + 1) < numberOfStoredBackups) {
-                    resetLastConfig(content);
-                    persistLastConfig(holder);
-                } else {
-                    String contentSubString = StringUtils.substringBefore(content, SEPARATOR_E);
-                    contentSubString = contentSubString.concat(SEPARATOR_E_PURE);
-                    content = StringUtils.substringAfter(content, contentSubString);
-                    resetLastConfig(content);
-                    persistLastConfig(holder);
-                }
-            }
-        }
-    }
-
-    private void resetLastConfig(String content) throws IOException {
-        content = content.replaceFirst(SEPARATOR_SL, SEPARATOR_S);
-        Files.write(content, storage, ENCODING);
-    }
-
-    private void persistLastConfig(ConfigSnapshotHolder holder) throws IOException {
-        Files.append(SEPARATOR_SL, storage, ENCODING);
-        String snapshotAsString = holder.getConfigSnapshot();
-        Files.append(newLine(snapshotAsString), storage, ENCODING);
-        Files.append(SEPARATOR_M, storage, ENCODING);
-        Files.append(toStringCaps(holder.getCapabilities()), storage, ENCODING);
-        Files.append(SEPARATOR_E, storage, ENCODING);
-    }
-
-    private CharSequence toStringCaps(Set<String> capabilities) {
-        StringBuilder b = new StringBuilder();
-        for (String capability : capabilities) {
-            b.append(newLine(capability));
-        }
-        return b.toString();
-    }
-
-    @Override
-    public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
-        Preconditions.checkNotNull(storage, "Storage file is null");
-
-        if (!storage.exists()) {
-            return Collections.emptyList();
-        }
-
-        final LineProcessor lineProcessor = new LineProcessor();
-        Files.readLines(storage, ENCODING, lineProcessor);
-
-        if (lineProcessor.getConfigSnapshot().isPresent() == false) {
-            return Collections.emptyList();
-        } else {
-            return Arrays.<ConfigSnapshotHolder>asList(new ConfigSnapshotHolderImpl(lineProcessor.getConfigSnapshot().get(),
-                    lineProcessor.getCapabilities(), storage.getAbsolutePath()));
-        }
-
-    }
-
-    private static final class LineProcessor implements com.google.common.io.LineProcessor<String> {
-
-        private boolean inLastConfig, inLastSnapshot;
-        private final StringBuffer snapshotBuffer = new StringBuffer();
-        private final SortedSet<String> caps = new TreeSet<>();
-
-        @Override
-        public String getResult() {
-            return null;
-        }
-
-        @Override
-        public boolean processLine(String line) throws IOException {
-            if (inLastConfig && line.equals(SEPARATOR_E_PURE)) {
-                inLastConfig = false;
-                return false;
-            }
-
-            if (inLastConfig && line.equals(SEPARATOR_M_PURE)) {
-                inLastSnapshot = false;
-                return true;
-            }
-
-            if (inLastConfig) {
-                if (inLastSnapshot) {
-                    snapshotBuffer.append(line);
-                    snapshotBuffer.append(System.lineSeparator());
-                } else {
-                    caps.add(line);
-                }
-            }
-
-            if (line.equals(SEPARATOR_SL_PURE)) {
-                inLastConfig = true;
-                inLastSnapshot = true;
-            }
-
-            return true;
-        }
-
-        Optional<String> getConfigSnapshot() {
-            final String xmlContent = snapshotBuffer.toString();
-            if (xmlContent.equals("")) {
-                return Optional.absent();
-            } else {
-                return Optional.of(xmlContent);
-            }
-        }
-
-        SortedSet<String> getCapabilities() {
-            return caps;
-        }
-
-    }
-
-    @Override
-    public void close() {
-
-    }
-
-    @Override
-    public String toString() {
-        return "FileStorageAdapter [storage=" + storage + "]";
-    }
-
-}
diff --git a/opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java b/opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java
deleted file mode 100644 (file)
index 0366dbc..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.config.persist.storage.file;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import java.io.File;
-import java.nio.file.Files;
-import java.util.Collection;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.config.persist.api.Persister;
-import org.opendaylight.controller.config.persist.test.PropertiesProviderTest;
-import static junit.framework.Assert.assertFalse;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-public class FileStorageAdapterTest {
-
-    private static int i;
-    private File file;
-
-    @Before
-    public void setUp() throws Exception {
-        file = Files.createTempFile("testFilePersist", ".txt").toFile();
-        if (!file.exists())
-            return;
-        com.google.common.io.Files.write("", file, Charsets.UTF_8);
-        i = 1;
-    }
-
-
-    @Test
-    public void testFileAdapterAsPersister() throws Exception {
-        FileStorageAdapter storage = new FileStorageAdapter();
-        PropertiesProviderTest pp = new PropertiesProviderTest();
-        pp.addProperty("fileStorage",file.getPath());
-        pp.addProperty("numberOfBackups",Integer.toString(Integer.MAX_VALUE));
-
-        Persister configPersister = storage.instantiate(pp);
-        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
-            @Override
-            public String getConfigSnapshot() {
-                return createConfig();
-            }
-
-            @Override
-            public SortedSet<String> getCapabilities() {
-                return createCaps();
-            }
-        };
-        configPersister.persistConfig(holder);
-
-        configPersister.persistConfig(holder);
-
-        Collection<String> readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8),
-                new Predicate<String>() {
-
-                    @Override
-                    public boolean apply(String input) {
-                        if (input.equals(""))
-                            return false;
-                        return true;
-                    }
-                });
-        assertEquals(14, readLines.size());
-
-        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
-        assertEquals(1, lastConf.size());
-        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
-        assertEquals("<config>2</config>",
-                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
-        assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
-    }
-    @Test
-    public void testFileAdapter() throws Exception {
-        FileStorageAdapter storage = new FileStorageAdapter();
-        storage.setFileStorage(file);
-        storage.setNumberOfBackups(Integer.MAX_VALUE);
-        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
-            @Override
-            public String getConfigSnapshot() {
-                return createConfig();
-            }
-
-            @Override
-            public SortedSet<String> getCapabilities() {
-                return createCaps();
-            }
-        };
-        storage.persistConfig(holder);
-
-        storage.persistConfig(holder);
-
-        Collection<String> readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8),
-                new Predicate<String>() {
-
-                    @Override
-                    public boolean apply(String input) {
-                        if (input.equals(""))
-                            return false;
-                        return true;
-                    }
-                });
-        assertEquals(14, readLines.size());
-
-        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
-        assertEquals(1, lastConf.size());
-        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
-        assertEquals("<config>2</config>",
-                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
-        assertEquals(createCaps(), configSnapshotHolder.getCapabilities());
-    }
-
-    private SortedSet<String> createCaps() {
-        SortedSet<String> caps = new TreeSet<>();
-
-        caps.add("cap1");
-        caps.add("cap2");
-        caps.add("capaaaa as dasfasdf s2");
-        return caps;
-    }
-
-    @Test
-    public void testFileAdapterOneBackup() throws Exception {
-        FileStorageAdapter storage = new FileStorageAdapter();
-        storage.setFileStorage(file);
-        storage.setNumberOfBackups(1);
-        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
-            @Override
-            public String getConfigSnapshot() {
-                return createConfig();
-            }
-
-            @Override
-            public SortedSet<String> getCapabilities() {
-                return createCaps();
-            }
-        };
-        storage.persistConfig(holder);
-
-        storage.persistConfig(holder);
-
-        Collection<String> readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8),
-                new Predicate<String>() {
-
-                    @Override
-                    public boolean apply(String input) {
-                        if (input.equals(""))
-                            return false;
-                        return true;
-                    }
-                });
-        assertEquals(7, readLines.size());
-
-        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
-        assertEquals(1, lastConf.size());
-        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
-        assertEquals("<config>2</config>",
-                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
-    }
-
-    @Test
-    public void testFileAdapterOnlyTwoBackups() throws Exception {
-        FileStorageAdapter storage = new FileStorageAdapter();
-        storage.setFileStorage(file);
-        storage.setNumberOfBackups(2);
-        final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() {
-            @Override
-            public String getConfigSnapshot() {
-                return createConfig();
-            }
-
-            @Override
-            public SortedSet<String> getCapabilities() {
-                return createCaps();
-            }
-        };
-        storage.persistConfig(holder);
-
-        storage.persistConfig(holder);
-        storage.persistConfig(holder);
-
-        Collection<String> readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8),
-                new Predicate<String>() {
-
-                    @Override
-                    public boolean apply(String input) {
-                        if (input.equals(""))
-                            return false;
-                        return true;
-                    }
-                });
-
-        assertEquals(14, readLines.size());
-
-        List<ConfigSnapshotHolder> lastConf = storage.loadLastConfigs();
-        assertEquals(1, lastConf.size());
-        ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0);
-        assertEquals("<config>3</config>",
-                configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", ""));
-        assertFalse(readLines.contains(holder.getConfigSnapshot()));
-    }
-
-    @Test
-    public void testNoLastConfig() throws Exception {
-        File file = Files.createTempFile("testFilePersist", ".txt").toFile();
-        if (!file.exists())
-            return;
-        FileStorageAdapter storage = new FileStorageAdapter();
-        storage.setFileStorage(file);
-
-        List<ConfigSnapshotHolder> elementOptional = storage.loadLastConfigs();
-        assertThat(elementOptional.size(), is(0));
-    }
-
-    @Test(expected = NullPointerException.class)
-    public void testNoProperties() throws Exception {
-        FileStorageAdapter storage = new FileStorageAdapter();
-        storage.loadLastConfigs();
-    }
-
-    @Test(expected = NullPointerException.class)
-    public void testNoProperties2() throws Exception {
-        FileStorageAdapter storage = new FileStorageAdapter();
-        storage.persistConfig(new ConfigSnapshotHolder() {
-            @Override
-            public String getConfigSnapshot() {
-                return Mockito.mock(String.class);
-            }
-
-            @Override
-            public SortedSet<String> getCapabilities() {
-                return new TreeSet<>();
-            }
-        } );
-    }
-
-    static String createConfig() {
-        return "<config>" + i++ + "</config>";
-    }
-
-}
index 6b55b6a..d700075 100644 (file)
@@ -23,7 +23,6 @@
         <module>config-plugin-parent</module>
         <module>config-util</module>
         <module>config-persister-api</module>
-        <module>config-persister-file-adapter</module>
         <module>config-persister-file-xml-adapter</module>
         <module>yang-jmx-generator</module>
         <module>yang-jmx-generator-plugin</module>
@@ -35,9 +34,7 @@
         <module>netty-threadgroup-config</module>
         <module>netty-event-executor-config</module>
         <module>netty-timer-config</module>
-        <module>config-persister-directory-adapter</module>
         <module>config-persister-directory-xml-adapter</module>
-        <module>config-persister-directory-autodetect-adapter</module>
         <module>yang-test-plugin</module>
         <module>shutdown-api</module>
         <module>shutdown-impl</module>
index a38a9b4..776fb7a 100644 (file)
                     <groupId>org.opendaylight.controller</groupId>
                     <artifactId>config-persister-api</artifactId>
                 </dependency>
-                <dependency>
-                    <groupId>org.opendaylight.controller</groupId>
-                    <artifactId>config-persister-file-adapter</artifactId>
-                </dependency>
                 <dependency>
                     <groupId>org.opendaylight.controller</groupId>
                     <artifactId>config-persister-file-xml-adapter</artifactId>
                 </dependency>
-                <dependency>
-                    <groupId>org.opendaylight.controller</groupId>
-                    <artifactId>config-persister-directory-adapter</artifactId>
-                </dependency>
                 <dependency>
                     <groupId>org.opendaylight.controller</groupId>
                     <artifactId>config-persister-directory-xml-adapter</artifactId>
                 </dependency>
-                <dependency>
-                    <groupId>org.opendaylight.controller</groupId>
-                    <artifactId>config-persister-directory-autodetect-adapter</artifactId>
-                </dependency>
 
                 <dependency>
                     <groupId>org.opendaylight.controller</groupId>
                     <artifactId>org.apache.xml.resolver</artifactId>
                     <version>1.2.0</version>
                 </dependency>
+                <dependency>
+                    <groupId>org.bouncycastle</groupId>
+                    <artifactId>bcprov-jdk15on</artifactId>
+                </dependency>
+                <dependency>
+                    <groupId>org.bouncycastle</groupId>
+                    <artifactId>bcpkix-jdk15on</artifactId>
+                </dependency>
 
                 <!-- threadpool -->
                 <dependency>
index 6f8878b..0ff4c9a 100644 (file)
@@ -69,6 +69,7 @@
       </directory>
       <excludes>
         <exclude>version.properties</exclude>
+        <exclude>configuration/config.ini</exclude>
       </excludes>
       <outputDirectory>
         opendaylight/
       <outputDirectory>opendaylight</outputDirectory>
       <filtered>true</filtered>
     </file>
+      <file>
+        <source>src/main/resources/configuration/config.ini</source>
+        <outputDirectory>opendaylight/configuration</outputDirectory>
+        <filtered>true</filtered>
+      </file>
   </files>
 </assembly>
diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/RSA.pk b/opendaylight/distribution/opendaylight/src/main/resources/configuration/RSA.pk
deleted file mode 100644 (file)
index c0266c7..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAuC9hbEacpewvylI0mwFwjy3Wou2hpr/ncN9BBiFDSaG5yW2k
-3Oy+SCAcFCL+ZKWb6cc6Ch4gUeCwyEHRojZguuhliKtak9YQf6qbvpPLe00842Lx
-iqNAGurMpzizCDsGFq8ChaAkBZQI3TvcHuPoSUWSMJ+K8xHpRyUdVr6g2yEjezKJ
-sTXBtWaeCCh6YUafFujuDJk7fvYcPW7Je5KRBBStIKvxcMW0zB+7eq04deTHwGbJ
-gGjKWilQ72hsDDP3Hbp5CJMAYg1r4GlCmFx3KyHRGztgWgNgaD7nNpKCkTLjtmA6
-b4x7TA+jrzZ6Af2z5TMrI4dv5w1SrxHaZ+ziLQIDAQABAoIBAHTndeGgq/rQf8De
-Do+4CTaHtK0zQSAyu/azbXUzlZ7drKuCEVs8VMY4wzmwwGEnkF+A2YDkgEUX5X0l
-8aYQ97KKoS9u+43MGCrAIhyDeGrpqlT1TzRcy+qJz53v6gq2U/X/3QztiQ+VV078
-mIluxNgE9XYxPaNsYfGLSCTv1+9c8y/hjGVX2kwFK+u4ut0ZZETggNa8UxfaHVDS
-fIJQX9Gm3J3GSUV30fDGMBIUW6ESLc2L8b7u8Mp9TRP39ZeQSuEUjBe8MYKv0Rel
-oEpjZvcnniMTpFbLpndBYn7/AoIiEBvtCN8faVTuRRcvvLcsRm09IctzKQYnMh6M
-6PLKV+ECgYEA8HFRYaKHUzxpzE/fyon82GQbzqFFY0/bbWrfWICMfNbIgshJUie6
-FmH5iUFMfeqaT7v557HFM0GB9FeIeSbvd88YmiBAcRopZ3DfMkDH+DT73yJ+/TKG
-2nrQtdhyuTIs4bwHqeS2BBJYs7PK9R2rratF3l34Tf7mjlvyOgygHdUCgYEAxBo2
-8hEBlAVNcNb1hTYUxe1w1B6675/mFlmw98Xmj9dRYfICXNhahs8tX3/lsBEd+vBu
-fI0oyHaff8m5bPgGzD1ZMybfeROujNrgxaKVk7Ef0FDRRCop4bm18OroFlFAt9l8
-wMp++ToACbdvQvL/mjWMPYlIxhB/YxHswICZZvkCgYAexxKYwdo6sGAGlC7cWT9x
-X5cjowcjyEQZRHXkeUgCbufpvcOM7aLnXJE5nY8yCwbHsBM0MlBA2GDPKylAANjk
-aDEJAZneIHAuWodngl1Wi0m2bU7+ECqs6s2uiU9eH2sZVh1RBQK7kLGkBx6ys6KX
-L3ZZGYRAT6GplWFzRsx0JQKBgCeVlxPD5QqpC1nEumi6YvUVGdpnnZpzL3HBhxxs
-wT612wKnZFyze4qM1X7ahVXGDsQxtkvD/sCAWW/lG13orw6ZL6FIroF1PJ3ILOkY
-CZN3hJF7TtKwpCWhZB2OfWzL2AGEkE8mUP0j/Q/5DCd6f6f0OSvOw3bfq6cm3iB5
-lP2ZAoGAXsRN5TZTX4AQ2xTlrDQ8A5XgcvyWQpJOmEXMTyHV7VaJVzmNWFVAvndK
-5UIq8ALDwB2t7vjmMUW6euvIwqtXiop7G79UOb3e3NhzeyWFGQyBLqCRznGaXQTT
-dlFy73xhukZMhFnj006bjKCYvOPnwuGl3+0fuWil5Rq3jOuY5c8=
------END RSA PRIVATE KEY-----
index 4598bac..9df653c 100644 (file)
@@ -8,7 +8,7 @@ osgi.bundles=\
     reference\:file\:../lib/slf4j-api-1.7.2.jar@1:start,\
     reference\:file\:../lib/logback-classic-1.0.9.jar@1:start,\
     reference\:file\:../lib/logback-core-1.0.9.jar@1:start,\
-    reference\:file\:../lib/logging.bridge-0.4.2-SNAPSHOT@1:start,\
+    reference\:file\:../lib/logging.bridge-${controller.version}@1:start,\
     reference\:file\:../lib/jersey-core-1.17.jar@2:start,\
     reference\:file\:../lib/jersey-server-1.17.jar@2:start
 
@@ -26,22 +26,12 @@ netconf.ssh.pk.path = ./configuration/RSA.pk
 
 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.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.autodetect.AutodetectDirectoryStorageAdapter
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
 netconf.config.persister.1.properties.directoryStorage=configuration/initial/
+# include only xml files, files with other extensions will be skipped, multiple extensions are permitted e.g. netconf.config.persister.1.properties.includeExtensions=xml,cfg,config
+netconf.config.persister.1.properties.includeExtensions=xml
 netconf.config.persister.1.readonly=true
 
-#netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
-#netconf.config.persister.3.properties.directoryStorage=configuration/initialXml/
-#netconf.config.persister.3.readonly=true
-
-#netconf.config.persister.4.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter
-#netconf.config.persister.4.properties.fileStorage=configuration/current/controller.currentconfig.txt
-#netconf.config.persister.4.properties.numberOfBackups=1
-
 netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
 netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml
 netconf.config.persister.2.properties.numberOfBackups=1
index 74e7d1a..01e5ae0 100644 (file)
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-file-adapter</artifactId>
+            <artifactId>config-persister-file-xml-adapter</artifactId>
             <version>${config.version}</version>
         </dependency>
         <dependency>
             <artifactId>config-persister-impl</artifactId>
             <version>${config.version}</version>
         </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-file-adapter</artifactId>
-            <version>${config.version}</version>
-        </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>netconf-impl</artifactId>
index 3e73f16..ffdcda3 100644 (file)
@@ -50,7 +50,7 @@
         </plugins>
         <pluginManagement>
             <plugins>
-                <!--This plugin's configuration is used to store Eclipse 
+                <!--This plugin's configuration is used to store Eclipse
                     m2e settings only. It has no influence on the Maven build itself. -->
                 <plugin>
                     <groupId>org.eclipse.m2e</groupId>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-data-api</artifactId>
         </dependency>
-        <!--dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-data-impl</artifactId> 
+        <!--dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-data-impl</artifactId>
             <version>${yangtools.version}</version> </dependency -->
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-file-adapter</artifactId>
+            <artifactId>config-persister-file-xml-adapter</artifactId>
             <version>${config.version}</version>
         </dependency>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <artifactId>pax-exam</artifactId>
             <version>${exam.version}</version>
-            <!-- Compile scope here is intentional, it is used in TestHelper 
-                class which could be downloaded via nexus and reused in other integration 
+            <!-- Compile scope here is intentional, it is used in TestHelper
+                class which could be downloaded via nexus and reused in other integration
                 tests. -->
             <scope>compile</scope>
         </dependency>
index 8ebf28f..fa478ac 100644 (file)
@@ -305,7 +305,7 @@ class RestconfImpl implements RestconfService {
         return callRpc(rpc, null)
     }
 
-    def resolveIdentifierInInvokeRpc(String identifier) {
+    private def resolveIdentifierInInvokeRpc(String identifier) {
         if (identifier.indexOf("/") === -1) {
             val identifierDecoded = identifier.urlPathArgDecode
             val rpc = identifierDecoded.rpcDefinition
@@ -314,8 +314,8 @@ class RestconfImpl implements RestconfService {
             }
             throw new ResponseException(NOT_FOUND, "RPC does not exist.");
         }
-        val slashErrorMsg  = String.format("Identifier %n%s%ncan't contain slash character (/). +
-            If slash is part of identifier name then use %2F placeholder.",identifier)
+        val slashErrorMsg = String.format(
+            "Identifier %n%s%ncan't contain slash character (/).%nIf slash is part of identifier name then use %%2F placeholder.", identifier)
         throw new ResponseException(NOT_FOUND, slashErrorMsg);
     }
 
index dff9d65..320a7f9 100644 (file)
@@ -7,20 +7,34 @@
  */
 package org.opendaylight.controller.sal.restconf.impl.test;
 
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import java.io.FileNotFoundException;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountService;
@@ -33,16 +47,12 @@ import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import static junit.framework.Assert.assertNotNull;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 public class RestGetOperationTest extends JerseyTest {
 
@@ -133,6 +143,52 @@ public class RestGetOperationTest extends JerseyTest {
         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
     }
 
+    /**
+     * MountPoint test. URI represents mount point.
+     * 
+     * Slashes in URI behind mount point. lst1 element with key
+     * GigabitEthernet0%2F0%2F0%2F0 (GigabitEthernet0/0/0/0) is requested via
+     * GET HTTP operation. It is tested whether %2F character is replaced with
+     * simple / in InstanceIdentifier parameter in method
+     * {@link BrokerFacade#readConfigurationDataBehindMountPoint(MountInstance, InstanceIdentifier)}
+     * which is called in method {@link RestconfImpl#readConfigurationData}
+     * 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void getDataWithSlashesBehindMountPoint() throws UnsupportedEncodingException, URISyntaxException,
+            ParseException {
+        InstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList();
+        when(
+                brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
+                        eq(awaitedInstanceIdentifier))).thenReturn(prepareCnDataForMountPointTest());
+        MountInstance mountInstance = mock(MountInstance.class);
+        when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
+        MountService mockMountService = mock(MountService.class);
+        when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
+
+        ControllerContext.getInstance().setMountService(mockMountService);
+
+        String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/lst1/GigabitEthernet0%2F0%2F0%2F0";
+        assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+    }
+
+    private InstanceIdentifier prepareInstanceIdentifierForList() throws URISyntaxException, ParseException {
+        List<PathArgument> parameters = new ArrayList<>();
+
+        Date revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-01-09");
+        URI uri = new URI("test:module");
+        QName qNameCont = QName.create(uri, revision, "cont");
+        QName qNameList = QName.create(uri, revision, "lst1");
+        QName qNameKeyList = QName.create(uri, revision, "lf11");
+
+        parameters.add(new InstanceIdentifier.NodeIdentifier(qNameCont));
+        parameters.add(new InstanceIdentifier.NodeIdentifierWithPredicates(qNameList, qNameKeyList,
+                "GigabitEthernet0/0/0/0"));
+        return new InstanceIdentifier(parameters);
+    }
+
     @Test
     public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
         when(
@@ -162,6 +218,7 @@ public class RestGetOperationTest extends JerseyTest {
         response = target(uri).request("application/yang.api+xml").get();
         validateModulesResponseXml(response);
     }
+
     // /streams/
     @Test
     public void getStreamsTest() throws UnsupportedEncodingException, FileNotFoundException {
@@ -193,7 +250,7 @@ public class RestGetOperationTest extends JerseyTest {
         assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
                 .find());
         String[] split = responseBody.split("<module");
-        assertEquals("<module element is returned more then once",2,split.length);
+        assertEquals("<module element is returned more then once", 2, split.length);
 
         response = target(uri).request("application/yang.api+json").get();
         assertEquals(200, response.getStatus());
@@ -201,7 +258,7 @@ public class RestGetOperationTest extends JerseyTest {
         assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
                 .find());
         split = responseBody.split("\"module\"");
-        assertEquals("\"module\" element is returned more then once",2,split.length);
+        assertEquals("\"module\" element is returned more then once", 2, split.length);
 
     }
 
@@ -395,8 +452,7 @@ public class RestGetOperationTest extends JerseyTest {
                 prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
                         responseBody).find());
         String[] split = responseBody.split("\"module\"");
-        assertEquals("\"module\" element is returned more then once",2,split.length);
-
+        assertEquals("\"module\" element is returned more then once", 2, split.length);
 
         response = target(uri).request("application/yang.api+xml").get();
         assertEquals(200, response.getStatus());
@@ -406,10 +462,7 @@ public class RestGetOperationTest extends JerseyTest {
                 prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
                         .find());
         split = responseBody.split("<module");
-        assertEquals("<module element is returned more then once",2,split.length);
-
-
-
+        assertEquals("<module element is returned more then once", 2, split.length);
 
     }
 
index 93342ea..2e533e7 100644 (file)
@@ -28,7 +28,13 @@ module test-module {
             type string;
         }
     }
-  } 
+    list lst1 {
+        key "lf11";
+        leaf lf11 {
+            type string;
+        }
+    }
+  }   
   
   
   rpc rpc-test {
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/pom.xml b/opendaylight/md-sal/samples/l2switch/implementation/pom.xml
new file mode 100644 (file)
index 0000000..c095eee
--- /dev/null
@@ -0,0 +1,92 @@
+<?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>sal-samples</artifactId>
+    <groupId>org.opendaylight.controller.samples</groupId>
+    <version>1.1-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+  <groupId>org.opendaylight.controller.samples.l2switch.md</groupId>
+  <artifactId>l2switch-impl</artifactId>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+
+          <instructions>
+            <Bundle-Activator>org.opendaylight.controller.sample.l2switch.md.L2SwitchProvider</Bundle-Activator>
+          </instructions>
+          <manifestLocation>${project.build.directory}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${junit.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.samples.l2switch.md</groupId>
+      <artifactId>l2switch-model</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-inventory</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+      <version>${yangtools.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-binding</artifactId>
+      <version>${yangtools.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>${mockito.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.thirdparty</groupId>
+      <artifactId>net.sf.jung2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-topology</artifactId>
+      <version>1.1-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/L2SwitchProvider.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/L2SwitchProvider.java
new file mode 100644 (file)
index 0000000..6f31a7e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md;
+
+import org.opendaylight.controller.sample.l2switch.md.addresstracker.AddressTracker;
+import org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterService;
+import org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterServiceImpl;
+import org.opendaylight.controller.sample.l2switch.md.inventory.InventoryService;
+import org.opendaylight.controller.sample.l2switch.md.packet.PacketHandler;
+import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphDijkstra;
+import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService;
+import org.opendaylight.controller.sample.l2switch.md.topology.TopologyLinkDataChangeHandler;
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.NotificationService;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * L2SwitchProvider serves as the Activator for our L2Switch OSGI bundle.
+ */
+public class L2SwitchProvider extends AbstractBindingAwareConsumer
+                              implements AutoCloseable {
+
+  private final static Logger _logger = LoggerFactory.getLogger(L2SwitchProvider.class);
+
+  private Registration<NotificationListener> listenerRegistration;
+  private AddressTracker addressTracker;
+  private TopologyLinkDataChangeHandler topologyLinkDataChangeHandler;
+
+
+  /**
+   * Setup the L2Switch.
+   * @param consumerContext  The context of the L2Switch.
+   */
+  @Override
+  public void onSessionInitialized(BindingAwareBroker.ConsumerContext consumerContext) {
+    DataBrokerService dataService = consumerContext.<DataBrokerService>getSALService(DataBrokerService.class);
+    addressTracker = new AddressTracker(dataService);
+
+    NetworkGraphService networkGraphService = new NetworkGraphDijkstra();
+    FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataService, networkGraphService);
+
+    NotificationService notificationService =
+            consumerContext.<NotificationService>getSALService(NotificationService.class);
+    PacketProcessingService packetProcessingService =
+            consumerContext.<PacketProcessingService>getRpcService(PacketProcessingService.class);
+    PacketHandler packetHandler = new PacketHandler();
+    packetHandler.setAddressTracker(addressTracker);
+    packetHandler.setFlowWriterService(flowWriterService);
+    packetHandler.setPacketProcessingService(packetProcessingService);
+    packetHandler.setInventoryService(new InventoryService(dataService));
+
+    this.listenerRegistration = notificationService.registerNotificationListener(packetHandler);
+    this.topologyLinkDataChangeHandler = new TopologyLinkDataChangeHandler(dataService, networkGraphService);
+    topologyLinkDataChangeHandler.registerAsDataChangeListener();
+  }
+
+  /**
+   * Cleanup the L2Switch.
+   * @throws Exception  occurs when the NotificationListener is closed
+   */
+  @Override
+  public void close() throws Exception {
+    if (listenerRegistration != null)
+      listenerRegistration.close();
+  }
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/addresstracker/AddressTracker.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/addresstracker/AddressTracker.java
new file mode 100644 (file)
index 0000000..ae5f031
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.addresstracker;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.L2Addresses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2AddressKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.Future;
+
+/**
+ * AddressTracker manages the MD-SAL data tree for L2Address (mac, node connector pairings) information.
+ */
+public class AddressTracker {
+
+  private final static Logger _logger = LoggerFactory.getLogger(AddressTracker.class);
+  private DataBrokerService dataService;
+
+  /**
+   * Construct an AddressTracker with the specified inputs
+   * @param dataService  The DataBrokerService for the AddressTracker
+   */
+  public AddressTracker(DataBrokerService dataService) {
+    this.dataService = dataService;
+  }
+
+  /**
+   * Get all the L2 Addresses in the MD-SAL data tree
+   * @return    All the L2 Addresses in the MD-SAL data tree
+   */
+  public L2Addresses getAddresses() {
+    return (L2Addresses)dataService.readOperationalData(InstanceIdentifier.<L2Addresses>builder(L2Addresses.class).toInstance());
+  }
+
+  /**
+   * Get a specific L2 Address in the MD-SAL data tree
+   * @param macAddress  A MacAddress associated with an L2 Address object
+   * @return    The L2 Address corresponding to the specified macAddress
+   */
+  public L2Address getAddress(MacAddress macAddress) {
+    return (L2Address) dataService.readOperationalData(createPath(macAddress));
+  }
+
+  /**
+   * Add L2 Address into the MD-SAL data tree
+   * @param macAddress  The MacAddress of the new L2Address object
+   * @param nodeConnectorRef  The NodeConnectorRef of the new L2Address object
+   * @return  Future containing the result of the add operation
+   */
+  public Future<RpcResult<TransactionStatus>> addAddress(MacAddress macAddress, NodeConnectorRef nodeConnectorRef) {
+    if(macAddress == null || nodeConnectorRef == null) {
+      return null;
+    }
+
+    // Create L2Address
+    final L2AddressBuilder builder = new L2AddressBuilder();
+    builder.setKey(new L2AddressKey(macAddress))
+            .setMac(macAddress)
+            .setNodeConnectorRef(nodeConnectorRef);
+
+    // Add L2Address to MD-SAL data tree
+    final DataModificationTransaction it = dataService.beginTransaction();
+    it.putOperationalData(createPath(macAddress), builder.build());
+    return it.commit();
+  }
+
+  /**
+   * Remove L2Address from the MD-SAL data tree
+   * @param macAddress  The MacAddress of an L2Address object
+   * @return  Future containing the result of the remove operation
+   */
+  public Future<RpcResult<TransactionStatus>> removeHost(MacAddress macAddress) {
+    final DataModificationTransaction it = dataService.beginTransaction();
+    it.removeOperationalData(createPath(macAddress));
+    return it.commit();
+  }
+
+  /**
+   * Create InstanceIdentifier path for an L2Address in the MD-SAL data tree
+   * @param macAddress  The MacAddress of an L2Address object
+   * @return  InstanceIdentifier of the L2Address corresponding to the specified macAddress
+   */
+  private InstanceIdentifier<L2Address> createPath(MacAddress macAddress) {
+    return InstanceIdentifier.<L2Addresses>builder(L2Addresses.class)
+            .<L2Address, L2AddressKey>child(L2Address.class, new L2AddressKey(macAddress)).toInstance();
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterService.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterService.java
new file mode 100644 (file)
index 0000000..2d5149e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.flow;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+
+/**
+ * Service that adds packet forwarding flows to configuration data store.
+ */
+public interface FlowWriterService {
+
+  /**
+   * Writes a flow that forwards packets to destPort if destination mac in packet is destMac and
+   * source Mac in packet is sourceMac. If sourceMac is null then flow would not set any source mac,
+   * resulting in all packets with destMac being forwarded to destPort.
+   *
+   * @param sourceMac
+   * @param destMac
+   * @param destNodeConnectorRef
+   */
+  public void addMacToMacFlow(MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destNodeConnectorRef);
+
+  /**
+   * Writes mac-to-mac flow on all ports that are in the path between given source and destination ports.
+   * It uses path provided by NetworkGraphService{@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService} to find a links{@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
+   * between given ports. And then writes appropriate flow on each port that is covered in that path.
+   *
+   * @param sourceMac
+   * @param sourceNodeConnectorRef
+   * @param destMac
+   * @param destNodeConnectorRef
+   */
+  public void addMacToMacFlowsUsingShortestPath(MacAddress sourceMac, NodeConnectorRef sourceNodeConnectorRef, MacAddress destMac, NodeConnectorRef destNodeConnectorRef);
+
+
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImpl.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImpl.java
new file mode 100644 (file)
index 0000000..f49771a
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.flow;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService;
+import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Implementation of FlowWriterService{@link org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterService},
+ * that builds required flow and writes to configuration data store using provided DataBrokerService
+ * {@link org.opendaylight.controller.sal.binding.api.data.DataBrokerService}
+ */
+public class FlowWriterServiceImpl implements FlowWriterService {
+  private static final Logger _logger = LoggerFactory.getLogger(FlowWriterServiceImpl.class);
+  private final DataBrokerService dataBrokerService;
+  private final NetworkGraphService networkGraphService;
+  private AtomicLong flowIdInc = new AtomicLong();
+  private AtomicLong flowCookieInc = new AtomicLong(0x2a00000000000000L);
+
+
+  public FlowWriterServiceImpl(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService) {
+    Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null.");
+    Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null.");
+    this.dataBrokerService = dataBrokerService;
+    this.networkGraphService = networkGraphService;
+  }
+
+  /**
+   * Writes a flow that forwards packets to destPort if destination mac in packet is destMac and
+   * source Mac in packet is sourceMac. If sourceMac is null then flow would not set any source mac,
+   * resulting in all packets with destMac being forwarded to destPort.
+   *
+   * @param sourceMac
+   * @param destMac
+   * @param destNodeConnectorRef
+   */
+  @Override
+  public void addMacToMacFlow(MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destNodeConnectorRef) {
+
+    Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
+    Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
+
+
+    // do not add flow if both macs are same.
+    if(sourceMac != null && destMac.equals(sourceMac)) {
+      _logger.info("In addMacToMacFlow: No flows added. Source and Destination mac are same.");
+      return;
+    }
+
+    // get flow table key
+    TableKey flowTableKey = new TableKey((short) 0); //TODO: Hard coded Table Id 0, need to get it from Configuration data.
+
+    //build a flow path based on node connector to program flow
+    InstanceIdentifier<Flow> flowPath = buildFlowPath(destNodeConnectorRef, flowTableKey);
+
+    // build a flow that target given mac id
+    Flow flowBody = createMacToMacFlow(flowTableKey.getId(), 0, sourceMac, destMac, destNodeConnectorRef);
+
+    // commit the flow in config data
+    writeFlowToConfigData(flowPath, flowBody);
+  }
+
+  /**
+   * Writes mac-to-mac flow on all ports that are in the path between given source and destination ports.
+   * It uses path provided by NetworkGraphService
+   * {@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService} to find a links
+   * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
+   * between given ports. And then writes appropriate flow on each port that is covered in that path.
+   *
+   * @param sourceMac
+   * @param sourceNodeConnectorRef
+   * @param destMac
+   * @param destNodeConnectorRef
+   */
+  @Override
+  public void addMacToMacFlowsUsingShortestPath(MacAddress sourceMac,
+                                                NodeConnectorRef sourceNodeConnectorRef,
+                                                MacAddress destMac,
+                                                NodeConnectorRef destNodeConnectorRef) {
+    Preconditions.checkNotNull(sourceMac, "Source mac address should not be null.");
+    Preconditions.checkNotNull(sourceNodeConnectorRef, "Source port should not be null.");
+    Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
+    Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
+
+    if(sourceNodeConnectorRef.equals(destNodeConnectorRef)) {
+      _logger.info("In addMacToMacFlowsUsingShortestPath: No flows added. Source and Destination ports are same.");
+      return;
+
+    }
+    NodeId sourceNodeId = new NodeId(sourceNodeConnectorRef.getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue());
+    NodeId destNodeId = new NodeId(destNodeConnectorRef.getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue());
+
+    // add destMac-To-sourceMac flow on source port
+    addMacToMacFlow(destMac, sourceMac, sourceNodeConnectorRef);
+
+    // add sourceMac-To-destMac flow on destination port
+    addMacToMacFlow(sourceMac, destMac, destNodeConnectorRef);
+
+    if(!sourceNodeId.equals(destNodeId)) {
+      List<Link> linksInBeween = networkGraphService.getPath(sourceNodeId, destNodeId);
+
+      if(linksInBeween != null) {
+        // assumes the list order is maintained and starts with link that has source as source node
+        for(Link link : linksInBeween) {
+          // add sourceMac-To-destMac flow on source port
+          addMacToMacFlow(sourceMac, destMac, getSourceNodeConnectorRef(link));
+
+          // add destMac-To-sourceMac flow on destination port
+          addMacToMacFlow(destMac, sourceMac, getDestNodeConnectorRef(link));
+        }
+      }
+    }
+  }
+
+  private NodeConnectorRef getSourceNodeConnectorRef(Link link) {
+    InstanceIdentifier<NodeConnector> nodeConnectorInstanceIdentifier
+        = InstanceIdentifierUtils.createNodeConnectorIdentifier(
+        link.getSource().getSourceNode().getValue(),
+        link.getSource().getSourceTp().getValue());
+    return new NodeConnectorRef(nodeConnectorInstanceIdentifier);
+  }
+
+  private NodeConnectorRef getDestNodeConnectorRef(Link link) {
+    InstanceIdentifier<NodeConnector> nodeConnectorInstanceIdentifier
+        = InstanceIdentifierUtils.createNodeConnectorIdentifier(
+        link.getDestination().getDestNode().getValue(),
+        link.getDestination().getDestTp().getValue());
+
+    return new NodeConnectorRef(nodeConnectorInstanceIdentifier);
+  }
+
+  /**
+   * @param nodeConnectorRef
+   * @return
+   */
+  private InstanceIdentifier<Flow> buildFlowPath(NodeConnectorRef nodeConnectorRef, TableKey flowTableKey) {
+
+    // generate unique flow key
+    FlowId flowId = new FlowId(String.valueOf(flowIdInc.getAndIncrement()));
+    FlowKey flowKey = new FlowKey(flowId);
+
+    return InstanceIdentifierUtils.generateFlowInstanceIdentifier(nodeConnectorRef, flowTableKey, flowKey);
+  }
+
+  /**
+   * @param tableId
+   * @param priority
+   * @param sourceMac
+   * @param destMac
+   * @param destPort
+   * @return {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder}
+   *         builds flow that forwards all packets with destMac to given port
+   */
+  private Flow createMacToMacFlow(Short tableId, int priority,
+                                  MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destPort) {
+
+    // start building flow
+    FlowBuilder macToMacFlow = new FlowBuilder() //
+        .setTableId(tableId) //
+        .setFlowName("mac2mac");
+
+    // use its own hash code for id.
+    macToMacFlow.setId(new FlowId(Long.toString(macToMacFlow.hashCode())));
+
+    // create a match that has mac to mac ethernet match
+    EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder() //
+        .setEthernetDestination(new EthernetDestinationBuilder() //
+            .setAddress(destMac) //
+            .build());
+    // set source in the match only if present
+    if(sourceMac != null) {
+      ethernetMatchBuilder.setEthernetSource(new EthernetSourceBuilder()
+          .setAddress(sourceMac)
+          .build());
+    }
+    EthernetMatch ethernetMatch = ethernetMatchBuilder.build();
+    Match match = new MatchBuilder()
+        .setEthernetMatch(ethernetMatch)
+        .build();
+
+
+    Uri destPortUri = destPort.getValue().firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
+
+    Action outputToControllerAction = new ActionBuilder() //
+        .setAction(new OutputActionCaseBuilder() //
+            .setOutputAction(new OutputActionBuilder() //
+                .setMaxLength(new Integer(0xffff)) //
+                .setOutputNodeConnector(destPortUri) //
+                .build()) //
+            .build()) //
+        .build();
+
+    // Create an Apply Action
+    ApplyActions applyActions = new ApplyActionsBuilder().setAction(ImmutableList.of(outputToControllerAction))
+        .build();
+
+    // Wrap our Apply Action in an Instruction
+    Instruction applyActionsInstruction = new InstructionBuilder() //
+        .setInstruction(new ApplyActionsCaseBuilder()//
+            .setApplyActions(applyActions) //
+            .build()) //
+        .build();
+
+    // Put our Instruction in a list of Instructions
+    macToMacFlow
+        .setMatch(match) //
+        .setInstructions(new InstructionsBuilder() //
+            .setInstruction(ImmutableList.of(applyActionsInstruction)) //
+            .build()) //
+        .setPriority(priority) //
+        .setBufferId(0L) //
+        .setHardTimeout(0) //
+        .setIdleTimeout(0) //
+        .setCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement()))
+        .setFlags(new FlowModFlags(false, false, false, false, false));
+
+    return macToMacFlow.build();
+  }
+
+  /**
+   * Starts and commits data change transaction which
+   * modifies provided flow path with supplied body.
+   *
+   * @param flowPath
+   * @param flowBody
+   * @return transaction commit
+   */
+  private Future<RpcResult<TransactionStatus>> writeFlowToConfigData(InstanceIdentifier<Flow> flowPath,
+                                                                     Flow flowBody) {
+    DataModificationTransaction addFlowTransaction = dataBrokerService.beginTransaction();
+    addFlowTransaction.putConfigurationData(flowPath, flowBody);
+    return addFlowTransaction.commit();
+  }
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/inventory/InventoryService.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/inventory/InventoryService.java
new file mode 100644 (file)
index 0000000..a12f394
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.inventory;
+
+import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.*;
+
+/**
+ * InventoryService provides functions related to Nodes & NodeConnectors.
+ */
+public class InventoryService {
+  private DataBrokerService dataService;
+  // Key: SwitchId, Value: NodeConnectorRef that corresponds to NC between controller & switch
+  private HashMap<String, NodeConnectorRef> controllerSwitchConnectors;
+
+  /**
+   * Construct an InventoryService object with the specified inputs.
+   * @param dataService  The DataBrokerService associated with the InventoryService.
+   */
+  public InventoryService(DataBrokerService dataService) {
+    this.dataService = dataService;
+    controllerSwitchConnectors = new HashMap<String, NodeConnectorRef>();
+  }
+
+  public HashMap<String, NodeConnectorRef> getControllerSwitchConnectors() {
+    return controllerSwitchConnectors;
+  }
+
+  // ToDo: Improve performance for thousands of switch ports
+  /**
+   * Get the External NodeConnectors of the network, which are the NodeConnectors connected to hosts.
+   * @return  The list of external node connectors.
+   */
+  public List<NodeConnectorRef> getExternalNodeConnectors() {
+    // External NodeConnectors = All - Internal
+    ArrayList<NodeConnectorRef> externalNodeConnectors = new ArrayList<NodeConnectorRef>();
+    Set<String> internalNodeConnectors = new HashSet<>();
+
+    // Read Topology -- find list of switch-to-switch internal node connectors
+    NetworkTopology networkTopology =
+        (NetworkTopology)dataService.readOperationalData(
+            InstanceIdentifier.<NetworkTopology>builder(NetworkTopology.class).toInstance());
+
+    for (Topology topology : networkTopology.getTopology()) {
+      Topology completeTopology =
+          (Topology)dataService.readOperationalData(
+              InstanceIdentifierUtils.generateTopologyInstanceIdentifier(
+                  topology.getTopologyId().getValue()));
+
+      for (Link link : completeTopology.getLink()) {
+        internalNodeConnectors.add(link.getDestination().getDestTp().getValue());
+        internalNodeConnectors.add(link.getSource().getSourceTp().getValue());
+      }
+    }
+
+    // Read Inventory -- contains list of all nodeConnectors
+    InstanceIdentifier.InstanceIdentifierBuilder<Nodes> nodesInsIdBuilder = InstanceIdentifier.<Nodes>builder(Nodes.class);
+    Nodes nodes = (Nodes)dataService.readOperationalData(nodesInsIdBuilder.toInstance());
+    if (nodes != null) {
+      for (Node node : nodes.getNode()) {
+        Node completeNode = (Node)dataService.readOperationalData(InstanceIdentifierUtils.createNodePath(node.getId()));
+        for (NodeConnector nodeConnector : completeNode.getNodeConnector()) {
+          // NodeConnector isn't switch-to-switch, so it must be controller-to-switch (internal) or external
+          if (!internalNodeConnectors.contains(nodeConnector.getId().getValue())) {
+            NodeConnectorRef ncRef = new NodeConnectorRef(
+                    InstanceIdentifier.<Nodes>builder(Nodes.class).<Node, NodeKey>child(Node.class, node.getKey())
+                            .<NodeConnector, NodeConnectorKey>child(NodeConnector.class, nodeConnector.getKey()).toInstance());
+
+            // External node connectors have "-" in their name for mininet, i.e. "s1-eth1"
+            if (nodeConnector.getAugmentation(FlowCapableNodeConnector.class).getName().contains("-")) {
+              externalNodeConnectors.add(ncRef);
+            }
+            // Controller-to-switch internal node connectors
+            else {
+              controllerSwitchConnectors.put(node.getId().getValue(), ncRef);
+            }
+          }
+        }
+      }
+    }
+
+    return externalNodeConnectors;
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/packet/PacketHandler.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/packet/PacketHandler.java
new file mode 100644 (file)
index 0000000..753de4a
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.packet;
+
+import org.opendaylight.controller.sample.l2switch.md.addresstracker.AddressTracker;
+import org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterService;
+import org.opendaylight.controller.sample.l2switch.md.inventory.InventoryService;
+import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils;
+import org.opendaylight.controller.sal.packet.Ethernet;
+import org.opendaylight.controller.sal.packet.LLDP;
+import org.opendaylight.controller.sal.packet.LinkEncap;
+import org.opendaylight.controller.sal.packet.Packet;
+import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * PacketHandler examines Ethernet packets to find L2Addresses (mac, nodeConnector) pairings
+ * of the sender and learns them.
+ * It also forwards the data packets appropriately dependending upon whether it knows about the
+ * target or not.
+ */
+public class PacketHandler implements PacketProcessingListener {
+
+  private final static Logger _logger = LoggerFactory.getLogger(PacketHandler.class);
+
+  private PacketProcessingService packetProcessingService;
+  private AddressTracker addressTracker;
+  private FlowWriterService flowWriterService;
+  private InventoryService inventoryService;
+
+  public void setAddressTracker(AddressTracker addressTracker) {
+    this.addressTracker = addressTracker;
+  }
+
+  public void setPacketProcessingService(PacketProcessingService packetProcessingService) {
+    this.packetProcessingService = packetProcessingService;
+  }
+
+  public void setFlowWriterService(FlowWriterService flowWriterService) {
+    this.flowWriterService = flowWriterService;
+  }
+
+  public void setInventoryService(InventoryService inventoryService) {
+    this.inventoryService = inventoryService;
+  }
+
+  /**
+   * The handler function for all incoming packets.
+   * @param packetReceived  The incoming packet.
+   */
+  @Override
+  public void onPacketReceived(PacketReceived packetReceived) {
+
+    if(packetReceived == null) return;
+
+    try {
+      byte[] payload = packetReceived.getPayload();
+      RawPacket rawPacket = new RawPacket(payload);
+      NodeConnectorRef ingress = packetReceived.getIngress();
+
+      Packet packet = decodeDataPacket(rawPacket);
+
+      if(!(packet instanceof Ethernet)) return;
+
+      handleEthernetPacket(packet, ingress);
+
+    } catch(Throwable _e) {
+      _e.printStackTrace();
+    }
+  }
+
+  /**
+   * The handler function for Ethernet packets.
+   * @param packet  The incoming Ethernet packet.
+   * @param ingress  The NodeConnector where the Ethernet packet came from.
+   */
+  private void handleEthernetPacket(Packet packet, NodeConnectorRef ingress) {
+    byte[] srcMac = ((Ethernet) packet).getSourceMACAddress();
+    byte[] destMac = ((Ethernet) packet).getDestinationMACAddress();
+
+    if (srcMac  == null || srcMac.length  == 0) return;
+
+    Object enclosedPacket = packet.getPayload();
+
+    if (enclosedPacket instanceof LLDP)
+      return; // LLDP packets are handled by OpenFlowPlugin
+
+    // get l2address by src mac
+    // if unknown, add l2address
+    MacAddress srcMacAddress = toMacAddress(srcMac);
+    L2Address src = addressTracker.getAddress(srcMacAddress);
+    boolean isSrcKnown = (src != null);
+    if (!isSrcKnown) {
+      addressTracker.addAddress(srcMacAddress, ingress);
+    }
+
+    // get host by dest mac
+    // if known set dest known to true
+    MacAddress destMacAddress = toMacAddress(destMac);
+    L2Address dest = addressTracker.getAddress(destMacAddress);
+    boolean isDestKnown = (dest != null);
+
+    byte[] payload = packet.getRawPayload();
+    // if (src and dest known)
+    // sendpacket to dest and add src<->dest flow
+    if(isSrcKnown & isDestKnown) {
+      flowWriterService.addMacToMacFlowsUsingShortestPath(srcMacAddress, src.getNodeConnectorRef(),
+          destMacAddress, dest.getNodeConnectorRef());
+      sendPacketOut(payload, getControllerNodeConnector(dest.getNodeConnectorRef()), dest.getNodeConnectorRef());
+    } else {
+      // if (dest unknown)
+      // sendpacket to external links minus ingress
+      floodExternalPorts(payload, ingress);
+    }
+  }
+
+  /**
+   * Floods the specified payload on external ports, which are ports not connected to switches.
+   * @param payload  The payload to be flooded.
+   * @param ingress  The NodeConnector where the payload came from.
+   */
+  private void floodExternalPorts(byte[] payload, NodeConnectorRef ingress) {
+    List<NodeConnectorRef> externalPorts = inventoryService.getExternalNodeConnectors();
+    externalPorts.remove(ingress);
+
+    for (NodeConnectorRef egress : externalPorts) {
+      sendPacketOut(payload, getControllerNodeConnector(egress), egress);
+    }
+  }
+
+  /**
+   * Sends the specified packet on the specified port.
+   * @param payload  The payload to be sent.
+   * @param ingress  The NodeConnector where the payload came from.
+   * @param egress  The NodeConnector where the payload will go.
+   */
+  private void sendPacketOut(byte[] payload, NodeConnectorRef ingress, NodeConnectorRef egress) {
+    if (ingress == null || egress == null)  return;
+    InstanceIdentifier<Node> egressNodePath = InstanceIdentifierUtils.getNodePath(egress.getValue());
+    TransmitPacketInput input = new TransmitPacketInputBuilder() //
+        .setPayload(payload) //
+        .setNode(new NodeRef(egressNodePath)) //
+        .setEgress(egress) //
+        .setIngress(ingress) //
+        .build();
+    packetProcessingService.transmitPacket(input);
+  }
+
+  /**
+   * Decodes an incoming packet.
+   * @param raw  The raw packet to be decoded.
+   * @return  The decoded form of the raw packet.
+   */
+  private Packet decodeDataPacket(RawPacket raw) {
+    if(raw == null) {
+      return null;
+    }
+    byte[] data = raw.getPacketData();
+    if(data.length <= 0) {
+      return null;
+    }
+    if(raw.getEncap().equals(LinkEncap.ETHERNET)) {
+      Ethernet res = new Ethernet();
+      try {
+        res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+        res.setRawPayload(raw.getPacketData());
+      } catch(Exception e) {
+        _logger.warn("Failed to decode packet: {}", e.getMessage());
+      }
+      return res;
+    }
+    return null;
+  }
+
+  /**
+   * Creates a MacAddress object out of a byte array.
+   * @param dataLinkAddress  The byte-array form of a MacAddress
+   * @return  MacAddress of the specified dataLinkAddress.
+   */
+  private MacAddress toMacAddress(byte[] dataLinkAddress) {
+    return new MacAddress(HexEncode.bytesToHexStringFormat(dataLinkAddress));
+  }
+
+  /**
+   * Gets the NodeConnector that connects the controller & switch for a specified switch port/node connector.
+   * @param nodeConnectorRef  The nodeConnector of a switch.
+   * @return  The NodeConnector that that connects the controller & switch.
+   */
+  private NodeConnectorRef getControllerNodeConnector(NodeConnectorRef nodeConnectorRef) {
+    NodeConnectorRef controllerSwitchNodeConnector = null;
+    HashMap<String, NodeConnectorRef> controllerSwitchConnectors = inventoryService.getControllerSwitchConnectors();
+    InstanceIdentifier<Node> nodePath = InstanceIdentifierUtils.getNodePath(nodeConnectorRef.getValue());
+    if (nodePath != null) {
+      NodeKey nodeKey = InstanceIdentifierUtils.getNodeKey(nodePath);
+      if (nodeKey != null) {
+        controllerSwitchNodeConnector = controllerSwitchConnectors.get(nodeKey.getId().getValue());
+      }
+    }
+    return controllerSwitchNodeConnector;
+  }
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstra.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstra.java
new file mode 100644 (file)
index 0000000..a90ac5a
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.topology;
+
+import com.google.common.base.Preconditions;
+import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath;
+import edu.uci.ics.jung.graph.DirectedSparseGraph;
+import edu.uci.ics.jung.graph.Graph;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Implementation of NetworkGraphService{@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService}.
+ * It uses Jung graph library internally to maintain a graph and optimum way to return shortest path using
+ * Dijkstra algorithm.
+ */
+public class NetworkGraphDijkstra implements NetworkGraphService {
+
+  private static final Logger _logger = LoggerFactory.getLogger(NetworkGraphDijkstra.class);
+
+  DijkstraShortestPath<NodeId, Link> shortestPath = null;
+  Graph<NodeId, Link> networkGraph = null;
+
+  /**
+   * Adds links to existing graph or creates new directed graph with given links if graph was not initialized.
+   * @param links
+   */
+  @Override
+  public synchronized void addLinks(List<Link> links) {
+    if(links == null || links.isEmpty()) {
+      _logger.info("In addLinks: No link added as links is null or empty.");
+      return;
+    }
+
+    if(networkGraph == null) {
+      networkGraph = new DirectedSparseGraph<>();
+    }
+
+    for(Link link : links) {
+      NodeId sourceNodeId = link.getSource().getSourceNode();
+      NodeId destinationNodeId = link.getDestination().getDestNode();
+      networkGraph.addVertex(sourceNodeId);
+      networkGraph.addVertex(destinationNodeId);
+      networkGraph.addEdge(link, sourceNodeId, destinationNodeId);
+    }
+    if(shortestPath == null) {
+      shortestPath = new DijkstraShortestPath<>(networkGraph);
+    } else {
+      shortestPath.reset();
+    }
+  }
+
+  /**
+   * removes links from existing graph.
+   * @param links
+   */
+  @Override
+  public synchronized void removeLinks(List<Link> links) {
+    Preconditions.checkNotNull(networkGraph, "Graph is not initialized, add links first.");
+
+    if(links == null || links.isEmpty()) {
+      _logger.info("In removeLinks: No link removed as links is null or empty.");
+      return;
+    }
+
+    for(Link link : links) {
+      networkGraph.removeEdge(link);
+    }
+
+    if(shortestPath == null) {
+      shortestPath = new DijkstraShortestPath<>(networkGraph);
+    } else {
+      shortestPath.reset();
+    }
+  }
+
+  /**
+   * returns a path between 2 nodes. Uses Dijkstra's algorithm to return shortest path.
+   * @param sourceNodeId
+   * @param destinationNodeId
+   * @return
+   */
+  @Override
+  public synchronized List<Link> getPath(NodeId sourceNodeId, NodeId destinationNodeId) {
+    Preconditions.checkNotNull(shortestPath, "Graph is not initialized, add links first.");
+
+    if(sourceNodeId == null || destinationNodeId == null) {
+      _logger.info("In getPath: returning null, as sourceNodeId or destinationNodeId is null.");
+      return null;
+    }
+
+    return shortestPath.getPath(sourceNodeId, destinationNodeId);
+  }
+
+  /**
+   * Clears the prebuilt graph, in case same service instance is required to process a new graph.
+   */
+  @Override
+  public synchronized void clear() {
+    networkGraph = null;
+    shortestPath = null;
+  }
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphService.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphService.java
new file mode 100644 (file)
index 0000000..173be34
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.topology;
+
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+
+import java.util.List;
+
+/**
+ * Service that allows to build a network graph using Topology links
+ * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
+ * and exposes operation that can be performed on such graph.
+ */
+public interface NetworkGraphService {
+
+  /**
+   * Adds links to existing graph or creates new graph with given links if graph was not initialized.
+   * @param links
+   */
+  public void addLinks(List<Link> links);
+
+  /**
+   * removes links from existing graph.
+   * @param links
+   */
+  public void removeLinks(List<Link> links);
+
+  /**
+   * returns a path between 2 nodes. Implementation should ideally return shortest path.
+   * @param sourceNodeId
+   * @param destinationNodeId
+   * @return
+   */
+  public List<Link> getPath(NodeId sourceNodeId, NodeId destinationNodeId);
+
+  /**
+   * Clears the prebuilt graph, in case same service instance is required to process a new graph.
+   */
+  public void clear();
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandler.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandler.java
new file mode 100644 (file)
index 0000000..254ebf8
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.topology;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Listens to data change events on topology links
+ * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
+ * and maintains a topology graph using provided NetworkGraphService
+ * {@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService}.
+ * It refreshes the graph after a delay(default 10 sec) to accommodate burst of change events if they come in bulk.
+ * This is to avoid continuous refresh of graph on a series of change events in short time.
+ */
+public class TopologyLinkDataChangeHandler implements DataChangeListener {
+  private static final Logger _logger = LoggerFactory.getLogger(TopologyLinkDataChangeHandler.class);
+  private static final String DEFAULT_TOPOLOGY_ID = "flow:1";
+
+  private boolean networkGraphRefreshScheduled = false;
+  private final ScheduledExecutorService networkGraphRefreshScheduler = Executors.newScheduledThreadPool(1);
+  private final long DEFAULT_GRAPH_REFRESH_DELAY = 10;
+  private final long graphRefreshDelayInSec;
+
+  private final NetworkGraphService networkGraphService;
+  private final DataBrokerService dataBrokerService;
+
+  /**
+   * Uses default delay to refresh topology graph if this constructor is used.
+   * @param dataBrokerService
+   * @param networkGraphService
+   */
+  public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService) {
+    Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null.");
+    Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null.");
+    this.dataBrokerService = dataBrokerService;
+    this.networkGraphService = networkGraphService;
+    this.graphRefreshDelayInSec = DEFAULT_GRAPH_REFRESH_DELAY;
+  }
+
+  /**
+   *
+   * @param dataBrokerService
+   * @param networkGraphService
+   * @param graphRefreshDelayInSec
+   */
+  public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService,
+                                       long graphRefreshDelayInSec) {
+    Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null.");
+    Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null.");
+    this.dataBrokerService = dataBrokerService;
+    this.networkGraphService = networkGraphService;
+    this.graphRefreshDelayInSec = graphRefreshDelayInSec;
+  }
+
+  /**
+   * Based on if links have been added or removed in topology data store, schedules a refresh of network graph.
+   * @param dataChangeEvent
+   */
+  @Override
+  public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> dataChangeEvent) {
+    if(dataChangeEvent == null) {
+      _logger.info("In onDataChanged: No Processing done as dataChangeEvent is null.");
+    }
+    Map<InstanceIdentifier<?>, DataObject> linkOriginalData = dataChangeEvent.getOriginalOperationalData();
+    Map<InstanceIdentifier<?>, DataObject> linkUpdatedData = dataChangeEvent.getUpdatedOperationalData();
+    // change this logic, once MD-SAL start populating DeletedOperationData Set
+    if(linkOriginalData != null && linkUpdatedData != null
+        && (linkOriginalData.size() != 0 || linkUpdatedData.size() != 0)
+        && !networkGraphRefreshScheduled) {
+      networkGraphRefreshScheduled = linkOriginalData.size() != linkUpdatedData.size();
+      if(networkGraphRefreshScheduled) {
+        networkGraphRefreshScheduler.schedule(new NetworkGraphRefresher(), graphRefreshDelayInSec, TimeUnit.SECONDS);
+      }
+    }
+
+  }
+
+  /**
+   * Registers as a data listener to receive changes done to
+   * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
+   * under {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology}
+   * operation data root.
+   */
+
+  public void registerAsDataChangeListener() {
+    InstanceIdentifier<Link> linkInstance = InstanceIdentifier.builder(NetworkTopology.class)
+        .child(Topology.class, new TopologyKey(new TopologyId(DEFAULT_TOPOLOGY_ID))).child(Link.class).toInstance();
+    dataBrokerService.registerDataChangeListener(linkInstance, this);
+  }
+
+  /**
+   *
+   */
+  private class NetworkGraphRefresher implements Runnable {
+    /**
+     *
+     */
+    @Override
+    public void run() {
+      networkGraphRefreshScheduled = false;
+      //TODO: it should refer to changed links only from DataChangeEvent above.
+      List<Link> links = getLinksFromTopology(DEFAULT_TOPOLOGY_ID);
+      networkGraphService.clear();// can remove this once changed links are addressed
+      if(links != null && !links.isEmpty()) {
+        networkGraphService.addLinks(links);
+      }
+    }
+
+    /**
+     * @param topologyId
+     * @return
+     */
+    private List<Link> getLinksFromTopology(String topologyId) {
+      InstanceIdentifier<Topology> topologyInstanceIdentifier = InstanceIdentifierUtils.generateTopologyInstanceIdentifier(topologyId);
+      Topology topology = (Topology) dataBrokerService.readOperationalData(topologyInstanceIdentifier);
+      return topology.getLink();
+    }
+  }
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/util/InstanceIdentifierUtils.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/util/InstanceIdentifierUtils.java
new file mode 100644 (file)
index 0000000..ea08f94
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.util;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/* InstanceIdentifierUtils provides utility functions related to InstanceIdentifiers.
+ */
+public class InstanceIdentifierUtils {
+
+  /**
+   * Creates an Instance Identifier (path) for node with specified id
+   *
+   * @param nodeId
+   * @return
+   */
+  public static final InstanceIdentifier<Node> createNodePath(NodeId nodeId) {
+    return InstanceIdentifier.builder(Nodes.class) //
+        .child(Node.class, new NodeKey(nodeId)) //
+        .build();
+  }
+
+  /**
+   * Shorten's node child path to node path.
+   *
+   * @param nodeChild child of node, from which we want node path.
+   * @return
+   */
+  public static final InstanceIdentifier<Node> getNodePath(InstanceIdentifier<?> nodeChild) {
+    return nodeChild.firstIdentifierOf(Node.class);
+  }
+
+
+  /**
+   * Creates a table path by appending table specific location to node path
+   *
+   * @param nodePath
+   * @param tableKey
+   * @return
+   */
+  public static final InstanceIdentifier<Table> createTablePath(InstanceIdentifier<Node> nodePath, TableKey tableKey) {
+    return InstanceIdentifier.builder(nodePath)
+        .augmentation(FlowCapableNode.class)
+        .child(Table.class, tableKey)
+        .build();
+  }
+
+  /**
+   * Creates a path for particular flow, by appending flow-specific information
+   * to table path.
+   *
+   * @param table
+   * @param flowKey
+   * @return
+   */
+  public static InstanceIdentifier<Flow> createFlowPath(InstanceIdentifier<Table> table, FlowKey flowKey) {
+    return InstanceIdentifier.builder(table)
+        .child(Flow.class, flowKey)
+        .build();
+  }
+
+  /**
+   * Extract table id from table path.
+   *
+   * @param tablePath
+   * @return
+   */
+  public static Short getTableId(InstanceIdentifier<Table> tablePath) {
+    return tablePath.firstKeyOf(Table.class, TableKey.class).getId();
+  }
+
+  /**
+   * Extracts NodeConnectorKey from node connector path.
+   */
+  public static NodeConnectorKey getNodeConnectorKey(InstanceIdentifier<?> nodeConnectorPath) {
+    return nodeConnectorPath.firstKeyOf(NodeConnector.class, NodeConnectorKey.class);
+  }
+
+  /**
+   * Extracts NodeKey from node path.
+   */
+  public static NodeKey getNodeKey(InstanceIdentifier<?> nodePath) {
+    return nodePath.firstKeyOf(Node.class, NodeKey.class);
+  }
+
+
+  //
+  public static final InstanceIdentifier<NodeConnector> createNodeConnectorIdentifier(String nodeIdValue,
+                                                                                      String nodeConnectorIdValue) {
+    return InstanceIdentifier.builder(createNodePath(new NodeId(nodeIdValue))) //
+        .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(nodeConnectorIdValue))) //
+        .build();
+  }
+
+  /**
+   * @param nodeConnectorRef
+   * @return
+   */
+  public static InstanceIdentifier<Node> generateNodeInstanceIdentifier(NodeConnectorRef nodeConnectorRef) {
+    return nodeConnectorRef.getValue().firstIdentifierOf(Node.class);
+  }
+
+  /**
+   * @param nodeConnectorRef
+   * @param flowTableKey
+   * @return
+   */
+  public static InstanceIdentifier<Table> generateFlowTableInstanceIdentifier(NodeConnectorRef nodeConnectorRef, TableKey flowTableKey) {
+    return InstanceIdentifier.builder(generateNodeInstanceIdentifier(nodeConnectorRef))
+        .augmentation(FlowCapableNode.class)
+        .child(Table.class, flowTableKey)
+        .build();
+  }
+
+  /**
+   * @param nodeConnectorRef
+   * @param flowTableKey
+   * @param flowKey
+   * @return
+   */
+  public static InstanceIdentifier<Flow> generateFlowInstanceIdentifier(NodeConnectorRef nodeConnectorRef,
+                                                                        TableKey flowTableKey,
+                                                                        FlowKey flowKey) {
+    return InstanceIdentifier.builder(generateFlowTableInstanceIdentifier(nodeConnectorRef, flowTableKey))
+        .child(Flow.class, flowKey)
+        .build();
+  }
+
+  public static InstanceIdentifier<Topology> generateTopologyInstanceIdentifier(String topologyId) {
+    return InstanceIdentifier.builder(NetworkTopology.class)
+        .child(Topology.class, new TopologyKey(new TopologyId(topologyId)))
+        .build();
+  }
+}
+
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImplTest.java b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImplTest.java
new file mode 100644 (file)
index 0000000..3520d81
--- /dev/null
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.flow;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ */
+public class FlowWriterServiceImplTest {
+  private DataBrokerService dataBrokerService;
+  private NodeConnectorRef srcNodeConnectorRef;
+  private NodeConnectorRef destNodeConnectorRef;
+  private MacAddress destMacAddress;
+  private MacAddress srcMacAddress;
+  private DataModificationTransaction dataModificationTransaction;
+  private NetworkGraphService networkGraphService;
+
+  @Before
+  public void init() {
+    dataBrokerService = mock(DataBrokerService.class);
+    networkGraphService = mock(NetworkGraphService.class);
+    //build source node connector ref
+    InstanceIdentifier<Nodes> srcNodesInstanceIdentifier
+        = InstanceIdentifier.builder(Nodes.class)
+        .build();
+    InstanceIdentifier<Node> srcNodeInstanceIdentifier
+        = InstanceIdentifier.builder(srcNodesInstanceIdentifier)
+        .child(Node.class, new NodeKey(new NodeId("openflow:1")))
+        .build();
+    InstanceIdentifier<NodeConnector> srcNodeConnectorInstanceIdentifier
+        = InstanceIdentifier.builder(srcNodeInstanceIdentifier)
+        .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId("openflow:1:2")))
+        .build();
+    srcNodeConnectorRef = new NodeConnectorRef(srcNodeConnectorInstanceIdentifier);
+
+    //build dest node connector ref
+    InstanceIdentifier<Nodes> nodesInstanceIdentifier
+        = InstanceIdentifier.builder(Nodes.class)
+        .build();
+    InstanceIdentifier<Node> nodeInstanceIdentifier
+        = InstanceIdentifier.builder(nodesInstanceIdentifier)
+        .child(Node.class, new NodeKey(new NodeId("openflow:2")))
+        .build();
+    InstanceIdentifier<NodeConnector> nodeConnectorInstanceIdentifier
+        = InstanceIdentifier.builder(nodeInstanceIdentifier)
+        .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId("openflow:2:2")))
+        .build();
+    destNodeConnectorRef = new NodeConnectorRef(nodeConnectorInstanceIdentifier);
+    destMacAddress = new MacAddress("00:0a:95:9d:68:16");
+    srcMacAddress = new MacAddress("00:0a:95:8c:97:24");
+    dataModificationTransaction = mock(DataModificationTransaction.class);
+    when(dataBrokerService.beginTransaction()).thenReturn(dataModificationTransaction);
+  }
+
+  @Test
+  public void testFlowWriterServiceImpl_NPEWhenDataBrokerServiceIsNull() throws Exception {
+    try {
+      new FlowWriterServiceImpl(null, networkGraphService);
+      fail("Expected null pointer exception.");
+    } catch(NullPointerException npe) {
+      assertEquals("dataBrokerService should not be null.", npe.getMessage());
+    }
+  }
+
+  @Test
+  public void testAddMacToMacFlow_NPEWhenNullSourceMacDestMacAndNodeConnectorRef() throws Exception {
+    FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService);
+    try {
+      flowWriterService.addMacToMacFlow(null, null, null);
+      fail("Expected null pointer exception.");
+    } catch(NullPointerException npe) {
+      assertEquals("Destination mac address should not be null.", npe.getMessage());
+    }
+  }
+
+  @Test
+  public void testAddMacToMacFlow_NPEWhenSourceMacNullMac() throws Exception {
+    FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService);
+    try {
+      flowWriterService.addMacToMacFlow(null, null, destNodeConnectorRef);
+      fail("Expected null pointer exception.");
+    } catch(NullPointerException npe) {
+      assertEquals("Destination mac address should not be null.", npe.getMessage());
+    }
+  }
+
+  @Test
+  public void testAddMacToMacFlow_NPEWhenNullSourceMacNodeConnectorRef() throws Exception {
+    FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService);
+    try {
+      flowWriterService.addMacToMacFlow(null, destMacAddress, null);
+      fail("Expected null pointer exception.");
+    } catch(NullPointerException npe) {
+      assertEquals("Destination port should not be null.", npe.getMessage());
+    }
+  }
+
+  @Test
+  public void testAddMacToMacFlow_WhenNullSourceMac() throws Exception {
+    FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService);
+    flowWriterService.addMacToMacFlow(null, destMacAddress, destNodeConnectorRef);
+    verify(dataBrokerService, times(1)).beginTransaction();
+    verify(dataModificationTransaction, times(1)).commit();
+  }
+
+  @Test
+  public void testAddMacToMacFlow_WhenSrcAndDestMacAreSame() throws Exception {
+    FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService);
+    flowWriterService.addMacToMacFlow(new MacAddress(destMacAddress.getValue()), destMacAddress, destNodeConnectorRef);
+    verify(dataBrokerService, never()).beginTransaction();
+    verify(dataModificationTransaction, never()).commit();
+
+  }
+
+  @Test
+  public void testAddMacToMacFlow_SunnyDay() throws Exception {
+    FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService);
+    flowWriterService.addMacToMacFlow(srcMacAddress, destMacAddress, destNodeConnectorRef);
+    verify(dataBrokerService, times(1)).beginTransaction();
+    verify(dataModificationTransaction, times(1)).commit();
+  }
+
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstraTest.java b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstraTest.java
new file mode 100644 (file)
index 0000000..3669a5c
--- /dev/null
@@ -0,0 +1,158 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.topology;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ */
+public class NetworkGraphDijkstraTest {
+  Link link1, link2, link3, link4, link5, link6, link7, link8, link9, link10,link11,link12;
+  Destination dest1, dest2, dest3, dest4, dest5, dest6,dest7,dest8,dest9,dest10,dest11,dest12;
+  Source src1, src2, src3, src4, src5, src6,src7,src8,src9,src10,src11,src12;
+  NodeId nodeId1 = new NodeId("openflow:1");
+  NodeId nodeId2 = new NodeId("openflow:2");
+  NodeId nodeId3 = new NodeId("openflow:3");
+  NodeId nodeId4 = new NodeId("openflow:4");
+  NodeId nodeId5 = new NodeId("openflow:5");
+  NodeId nodeId6 = new NodeId("openflow:6");
+  NodeId nodeId7 = new NodeId("openflow:7");
+  List<Link> links = new ArrayList<>();
+
+  @Before
+  public void init() {
+    link1 = mock(Link.class);
+    link2 = mock(Link.class);
+    link3 = mock(Link.class);
+    link4 = mock(Link.class);
+    link5 = mock(Link.class);
+    link6 = mock(Link.class);
+    link7 = mock(Link.class);
+    link8 = mock(Link.class);
+    link9 = mock(Link.class);
+    link10 = mock(Link.class);
+    link11 = mock(Link.class);
+    link12 = mock(Link.class);
+    dest1 = mock(Destination.class);
+    dest2 = mock(Destination.class);
+    dest3 = mock(Destination.class);
+    dest4 = mock(Destination.class);
+    dest5 = mock(Destination.class);
+    dest6 = mock(Destination.class);
+    dest7 = mock(Destination.class);
+    dest8 = mock(Destination.class);
+    dest9 = mock(Destination.class);
+    dest10 = mock(Destination.class);
+    dest11 = mock(Destination.class);
+    dest12 = mock(Destination.class);
+    src1 = mock(Source.class);
+    src2 = mock(Source.class);
+    src3 = mock(Source.class);
+    src4 = mock(Source.class);
+    src5 = mock(Source.class);
+    src6 = mock(Source.class);
+    src7 = mock(Source.class);
+    src8 = mock(Source.class);
+    src9 = mock(Source.class);
+    src10 = mock(Source.class);
+    src11 = mock(Source.class);
+    src12 = mock(Source.class);
+    when(link1.getSource()).thenReturn(src1);
+    when(link2.getSource()).thenReturn(src2);
+    when(link3.getSource()).thenReturn(src3);
+    when(link4.getSource()).thenReturn(src4);
+    when(link5.getSource()).thenReturn(src5);
+    when(link6.getSource()).thenReturn(src6);
+    when(link7.getSource()).thenReturn(src7);
+    when(link8.getSource()).thenReturn(src8);
+    when(link9.getSource()).thenReturn(src9);
+    when(link10.getSource()).thenReturn(src10);
+    when(link11.getSource()).thenReturn(src11);
+    when(link12.getSource()).thenReturn(src12);
+    when(link1.getDestination()).thenReturn(dest1);
+    when(link2.getDestination()).thenReturn(dest2);
+    when(link3.getDestination()).thenReturn(dest3);
+    when(link4.getDestination()).thenReturn(dest4);
+    when(link5.getDestination()).thenReturn(dest5);
+    when(link6.getDestination()).thenReturn(dest6);
+    when(link7.getDestination()).thenReturn(dest7);
+    when(link8.getDestination()).thenReturn(dest8);
+    when(link9.getDestination()).thenReturn(dest9);
+    when(link10.getDestination()).thenReturn(dest10);
+    when(link11.getDestination()).thenReturn(dest11);
+    when(link12.getDestination()).thenReturn(dest12);
+    when(src1.getSourceNode()).thenReturn(nodeId1);
+    when(dest1.getDestNode()).thenReturn(nodeId2);
+    when(src2.getSourceNode()).thenReturn(nodeId2);
+    when(dest2.getDestNode()).thenReturn(nodeId1);
+    when(src3.getSourceNode()).thenReturn(nodeId1);
+    when(dest3.getDestNode()).thenReturn(nodeId3);
+    when(src4.getSourceNode()).thenReturn(nodeId3);
+    when(dest4.getDestNode()).thenReturn(nodeId1);
+    when(src5.getSourceNode()).thenReturn(nodeId2);
+    when(dest5.getDestNode()).thenReturn(nodeId4);
+    when(src6.getSourceNode()).thenReturn(nodeId4);
+    when(dest6.getDestNode()).thenReturn(nodeId2);
+    when(src7.getSourceNode()).thenReturn(nodeId2);
+    when(dest7.getDestNode()).thenReturn(nodeId5);
+    when(src8.getSourceNode()).thenReturn(nodeId5);
+    when(dest8.getDestNode()).thenReturn(nodeId2);
+    when(src9.getSourceNode()).thenReturn(nodeId6);
+    when(dest9.getDestNode()).thenReturn(nodeId3);
+    when(src10.getSourceNode()).thenReturn(nodeId3);
+    when(dest10.getDestNode()).thenReturn(nodeId6);
+    when(src11.getSourceNode()).thenReturn(nodeId7);
+    when(dest11.getDestNode()).thenReturn(nodeId3);
+    when(src12.getSourceNode()).thenReturn(nodeId3);
+    when(dest12.getDestNode()).thenReturn(nodeId7);
+    links.add(link1);
+    links.add(link2);
+    links.add(link3);
+    links.add(link4);
+    links.add(link5);
+    links.add(link6);
+    links.add(link7);
+    links.add(link8);
+    links.add(link9);
+    links.add(link10);
+    links.add(link11);
+    links.add(link12);
+
+  }
+
+  @Test
+  public void testAddLinksAndGetPath() throws Exception {
+    NetworkGraphService networkGraphService = new NetworkGraphDijkstra();
+    networkGraphService.addLinks(links);
+    List<Link> path = networkGraphService.getPath(nodeId2, nodeId3);
+    assertEquals("path size is not as expected.", 2, path.size());
+    assertEquals("link source is not as expected.", nodeId2, path.get(0).getSource().getSourceNode());
+    assertEquals("link destination is not as expected.", nodeId1, path.get(0).getDestination().getDestNode());
+    path = networkGraphService.getPath(nodeId3, nodeId2);
+    assertEquals("path size is not as expected.", 2, path.size());
+    assertEquals("link source is not as expected.", nodeId3, path.get(0).getSource().getSourceNode());
+    assertEquals("link destination is not as expected.", nodeId1, path.get(0).getDestination().getDestNode());
+
+    path = networkGraphService.getPath(nodeId4, nodeId6);
+    assertEquals("path size is not as expected.", 4, path.size());
+    assertEquals("link source is not as expected.", nodeId4, path.get(0).getSource().getSourceNode());
+    assertEquals("link destination is not as expected.", nodeId2, path.get(0).getDestination().getDestNode());
+  }
+}
diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandlerTest.java b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandlerTest.java
new file mode 100644 (file)
index 0000000..9ecd256
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sample.l2switch.md.topology;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ */
+public class TopologyLinkDataChangeHandlerTest {
+  NetworkGraphService networkGraphService;
+  DataBrokerService dataBrokerService;
+  DataChangeEvent dataChangeEvent;
+  Topology topology;
+  Link link;
+
+  @Before
+  public void init() {
+    networkGraphService = mock(NetworkGraphService.class);
+    dataBrokerService = mock(DataBrokerService.class);
+    dataChangeEvent = mock(DataChangeEvent.class);
+    link = mock(Link.class);
+    topology = mock(Topology.class);
+  }
+
+  @Test
+  public void testOnDataChange() throws Exception {
+    TopologyLinkDataChangeHandler topologyLinkDataChangeHandler = new TopologyLinkDataChangeHandler(dataBrokerService, networkGraphService, 2);
+    Map<InstanceIdentifier<?>, DataObject> original = new HashMap<InstanceIdentifier<?>, DataObject>();
+    InstanceIdentifier<?> instanceIdentifier = InstanceIdentifierUtils.generateTopologyInstanceIdentifier("flow:1");
+    DataObject dataObject = mock(DataObject.class);
+    Map<InstanceIdentifier<?>, DataObject> updated = new HashMap<InstanceIdentifier<?>, DataObject>();
+    updated.put(instanceIdentifier, dataObject);
+    when(dataChangeEvent.getUpdatedOperationalData()).thenReturn(updated);
+    when(dataChangeEvent.getOriginalOperationalData()).thenReturn(original);
+    List<Link> links = new ArrayList<>();
+    links.add(link);
+    when(dataBrokerService.readOperationalData(instanceIdentifier)).thenReturn(topology);
+    when(topology.getLink()).thenReturn(links);
+
+    topologyLinkDataChangeHandler.onDataChanged(dataChangeEvent);
+    Thread.sleep(2100);
+    verify(networkGraphService, times(1)).addLinks(links);
+  }
+}
diff --git a/opendaylight/md-sal/samples/l2switch/model/pom.xml b/opendaylight/md-sal/samples/l2switch/model/pom.xml
new file mode 100644 (file)
index 0000000..d0ef2e0
--- /dev/null
@@ -0,0 +1,97 @@
+<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>sal-samples</artifactId>
+    <groupId>org.opendaylight.controller.samples</groupId>
+    <version>1.1-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+  <groupId>org.opendaylight.controller.samples.l2switch.md</groupId>
+  <artifactId>l2switch-model</artifactId>
+  <packaging>bundle</packaging>
+
+  <build>
+         <plugins>
+                 <plugin>
+                         <groupId>org.apache.felix</groupId>
+                         <artifactId>maven-bundle-plugin</artifactId>
+                         <extensions>true</extensions>
+                         <configuration>
+                           <instructions>
+                             <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                             <Import-Package>org.opendaylight.yangtools.yang.binding.annotations, *</Import-Package>
+                             <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                           </instructions>
+                         </configuration>
+                       </plugin>
+                 <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+        <version>${yangtools.version}</version>
+        <executions>
+            <execution>
+                <goals>
+                    <goal>generate-sources</goal>
+                </goals>
+                <configuration>
+                    <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                    <codeGenerators>
+                        <generator>
+                            <codeGeneratorClass>
+                                org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+                            </codeGeneratorClass>
+                            <outputBaseDir>
+                                target/generated-sources/sal
+                            </outputBaseDir>
+                        </generator>
+                        <generator>
+                            <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+                            <outputBaseDir>target/site/models</outputBaseDir>
+                        </generator>
+                        <generator>
+                            <codeGeneratorClass>org.opendaylight.yangtools.yang.wadl.generator.maven.WadlGenerator</codeGeneratorClass>
+                            <outputBaseDir>target/site/models</outputBaseDir>
+                        </generator>
+                    </codeGenerators>
+                    <inspectDependencies>true</inspectDependencies>
+                </configuration>
+            </execution>
+        </executions>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>maven-sal-api-gen-plugin</artifactId>
+                <version>${yangtools.version}</version>
+                <type>jar</type>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-binding</artifactId>
+                <version>${yangtools.version}</version>
+                <type>jar</type>
+            </dependency>
+        </dependencies>
+                         
+                       </plugin>
+               </plugins>
+       </build>
+       
+       <dependencies>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-binding</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-common</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools.model</groupId>
+          <artifactId>ietf-yang-types</artifactId>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller.model</groupId>
+        <artifactId>model-inventory</artifactId>
+      </dependency>
+  </dependencies>
+</project>
diff --git a/opendaylight/md-sal/samples/l2switch/model/src/main/yang/l2-address-tracker.yang b/opendaylight/md-sal/samples/l2switch/model/src/main/yang/l2-address-tracker.yang
new file mode 100644 (file)
index 0000000..d694c68
--- /dev/null
@@ -0,0 +1,45 @@
+module l2-address-tracker {
+  yang-version 1;
+  namespace "urn:opendaylight:l2-address-tracker";
+  prefix l2-address-tracker;
+
+  import ietf-yang-types {
+    prefix yang;
+    revision-date 2010-09-24;
+  }
+  import opendaylight-inventory {
+    prefix inv;
+    revision-date 2013-08-19;
+  }
+
+  organization "Cisco Systems Inc";
+  contact
+    "Alex Fan <alefan@cisco.com>";
+  description
+    "YANG version of the  L2 Address Tracker Data Model";
+
+  revision 2014-04-02 {
+    description
+      "L2 Address Tracker module draft.";
+  }
+
+  grouping l2-address {
+    leaf mac {
+        type yang:mac-address;
+        mandatory true;
+        description
+          "the mac address of the host.";
+    }
+    leaf node-connector-ref {
+      type inv:node-connector-ref;
+    }
+  }
+
+  container l2-addresses {
+    config false;
+    list l2-address {
+      key "mac";
+      uses l2-address;
+    }
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/samples/l2switch/pom.xml b/opendaylight/md-sal/samples/l2switch/pom.xml
new file mode 100644 (file)
index 0000000..2e2100b
--- /dev/null
@@ -0,0 +1,18 @@
+<?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>
+
+
+  <artifactId>l2switch.aggregator</artifactId>
+  <groupId>org.opendaylight.controller.samples.l2switch</groupId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>model</module>
+    <module>implementation</module>
+  </modules>
+
+</project>
index 5481026..9f9d9d3 100644 (file)
@@ -19,6 +19,7 @@
                <module>toaster</module>
                <module>toaster-consumer</module>
                <module>toaster-provider</module>
+    <module>l2switch</module>
   </modules>
 
     <profiles>
index a9fc739..f0a8584 100644 (file)
@@ -43,7 +43,7 @@
         </plugins>
         <pluginManagement>
             <plugins>
-                <!--This plugin's configuration is used to store Eclipse 
+                <!--This plugin's configuration is used to store Eclipse
                     m2e settings only. It has no influence on the Maven build itself. -->
                 <plugin>
                     <groupId>org.eclipse.m2e</groupId>
             <artifactId>jersey-core</artifactId>
             <version>${jersey.version}</version>
         </dependency>
-        <!-- <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-servlet</artifactId> 
+        <!-- <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-servlet</artifactId>
             <version>${jersey.version}</version> </dependency> -->
         <dependency>
             <groupId>com.sun.jersey</groupId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-persister-file-adapter</artifactId>
+            <artifactId>config-persister-file-xml-adapter</artifactId>
             <version>${config.version}</version>
         </dependency>
         <dependency>
index 8400bc1..4a43e0c 100644 (file)
@@ -75,9 +75,9 @@ public class ServiceProviderController {
         InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH)
                 .nodeWithKey(InventoryUtils.INVENTORY_NODE, InventoryUtils.INVENTORY_ID, "foo").toInstance();
 
-        
+
         InstanceIdentifier mountPointPath = path;
-        
+
         /** We retrive a mountpoint **/
         MountProvisionInstance mountPoint = mountService.getMountPoint(mountPointPath);
         CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES)
@@ -215,7 +215,7 @@ public class ServiceProviderController {
                 mavenBundle(ODL, "yang-jmx-generator").versionAsInProject(),
                 mavenBundle(ODL, "logback-config").versionAsInProject(),
                 mavenBundle(ODL, "config-persister-api").versionAsInProject(),
-                // mavenBundle(ODL,"config-persister-file-adapter").versionAsInProject(),
+                // mavenBundle(ODL,"config-persister-file-xml-adapter").versionAsInProject(),
                 mavenBundle(ODL, "protocol-framework").versionAsInProject(),
                 mavenBundle(ODL, "netconf-api").versionAsInProject(),
                 mavenBundle(ODL, "netconf-impl").versionAsInProject(),
index c1cad4a..31a4f08 100644 (file)
@@ -37,12 +37,12 @@ import java.util.ListIterator;
  netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
  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.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
  netconf.config.persister.2.readonly=true
- netconf.config.persister.2.properties.fileStorage=configuration/current/controller.config.1.txt
+ netconf.config.persister.2.properties.fileStorage=configuration/current/controller.config.1.xml
 
- 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.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
+ netconf.config.persister.3.properties.fileStorage=configuration/current/controller.config.2.xml
  netconf.config.persister.3.properties.numberOfBackups=3
 
  </pre>
index 677d0df..4ca9690 100644 (file)
@@ -8,33 +8,13 @@
 
 package org.opendaylight.controller.netconf.it;
 
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import io.netty.channel.ChannelFuture;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-
 import junit.framework.Assert;
-
+import org.apache.commons.io.IOUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -42,7 +22,6 @@ import org.junit.Test;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
 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;
@@ -52,6 +31,7 @@ import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.client.NetconfClient;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
@@ -72,17 +52,34 @@ import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
 
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
+import javax.management.ObjectName;
+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.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 public class NetconfITTest extends AbstractNetconfConfigTest {
 
     // TODO refactor, pull common code up to AbstractNetconfITTest
 
-    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);
@@ -90,7 +87,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     private static final String PASSWORD = "netconf";
 
     private NetconfMessage getConfig, getConfigCandidate, editConfig,
-    closeSession, startExi, stopExi;
+            closeSession, startExi, stopExi;
     private DefaultCommitNotificationProducer commitNot;
     private NetconfServerDispatcher dispatch;
 
@@ -113,7 +110,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         ChannelFuture s = dispatch.createServer(tcpAddress);
         s.await();
 
-        clientDispatcher = new NetconfClientDispatcher( nettyThreadgroup, nettyThreadgroup, 5000);
+        clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
     }
 
     private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
@@ -164,13 +161,14 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
                 yangDependencies.add(resourceAsStream);
             }
         }
-        assertEquals("Some yang files were not found",emptyList(), failedToFind);
+        assertEquals("Some yang files were not found", emptyList(), failedToFind);
         return yangDependencies;
     }
 
     protected List<ModuleFactory> getModuleFactories() {
         return getModuleFactoriesS();
     }
+
     static List<ModuleFactory> getModuleFactoriesS() {
         return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
                 new NetconfTestImplModuleFactory());
@@ -193,7 +191,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testTwoSessions() throws Exception {
-        try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher))  {
+        try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher)) {
             try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 10000, clientDispatcher)) {
             }
         }
@@ -258,7 +256,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         NetconfTestImplModuleMXBean proxy = configRegistryClient
                 .newMXBeanProxy(impl, NetconfTestImplModuleMXBean.class);
         proxy.setTestingDep(dep);
-        proxy.setSimpleShort((short)0);
+        proxy.setSimpleShort((short) 0);
 
         transaction.commit();
 
@@ -400,12 +398,15 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         return netconfClient;
     }
 
-    private void startSSHServer() throws Exception{
+    private void startSSHServer() throws Exception {
         logger.info("Creating SSH server");
-        StubUserManager um = new StubUserManager(USERNAME,PASSWORD);
-        InputStream is = getClass().getResourceAsStream("/RSA.pk");
-        AuthProvider ap = new AuthProvider(um, is);
-        Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress,ap));
+        StubUserManager um = new StubUserManager(USERNAME, PASSWORD);
+        String pem;
+        try (InputStream is = getClass().getResourceAsStream("/RSA.pk")) {
+            pem = IOUtils.toString(is);
+        }
+        AuthProvider ap = new AuthProvider(um, pem);
+        Thread sshServerThread = new Thread(NetconfSSHServer.start(10830, tcpAddress, ap));
         sshServerThread.setDaemon(true);
         sshServerThread.start();
         logger.info("SSH server on");
@@ -415,11 +416,11 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     public void sshTest() throws Exception {
         startSSHServer();
         logger.info("creating connection");
-        Connection conn = new Connection(sshAddress.getHostName(),sshAddress.getPort());
+        Connection conn = new Connection(sshAddress.getHostName(), sshAddress.getPort());
         Assert.assertNotNull(conn);
         logger.info("connection created");
         conn.connect();
-        boolean isAuthenticated = conn.authenticateWithPassword(USERNAME,PASSWORD);
+        boolean isAuthenticated = conn.authenticateWithPassword(USERNAME, PASSWORD);
         assertTrue(isAuthenticated);
         logger.info("user authenticated");
         final Session sess = conn.openSession();
@@ -427,10 +428,10 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         logger.info("user authenticated");
         sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes());
 
-        new Thread(){
+        new Thread() {
             @Override
-            public void run(){
-                while (true){
+            public void run() {
+                while (true) {
                     byte[] bytes = new byte[1024];
                     int c = 0;
                     try {
@@ -438,8 +439,10 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
                     } 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;
+                    logger.info("got data:" + bytes);
+                    if (c == 0) {
+                        break;
+                    }
                 }
             }
         }.join();
index 73e0a46..23a69b2 100644 (file)
@@ -1,4 +1,5 @@
-<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">
+<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>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>usermanager</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -58,7 +72,8 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Bundle-Activator>org.opendaylight.controller.netconf.osgi.NetconfSSHActivator</Bundle-Activator>
+                        <Bundle-Activator>org.opendaylight.controller.netconf.ssh.osgi.NetconfSSHActivator
+                        </Bundle-Activator>
                         <Import-Package>
                             com.google.common.base,
                             ch.ethz.ssh2,
@@ -71,6 +86,7 @@
                             org.osgi.framework,
                             org.osgi.util.tracker,
                             org.slf4j,
+                            org.bouncycastle.openssl
                         </Import-Package>
                     </instructions>
                 </configuration>
index 3d53180..2d38048 100644 (file)
@@ -7,64 +7,48 @@
  */
 package org.opendaylight.controller.netconf.ssh.authentication;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.sal.authorization.AuthResultEnum;
 import org.opendaylight.controller.sal.authorization.UserLevel;
 import org.opendaylight.controller.usermanager.IUserManager;
 import org.opendaylight.controller.usermanager.UserConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
 
 public class AuthProvider implements AuthProviderInterface {
 
-    private static IUserManager um;
+    private static IUserManager um; //FIXME static mutable state, no locks
     private static final String DEFAULT_USER = "netconf";
     private static final String DEFAULT_PASSWORD = "netconf";
-    private String PEM;
-
-    private static final Logger logger =  LoggerFactory.getLogger(AuthProvider.class);
-
-    public AuthProvider(IUserManager ium,InputStream privateKeyFileInputStream) throws Exception {
+    private final String pem;
 
+    public AuthProvider(IUserManager ium, String pemCertificate) throws Exception {
+        checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null");
         AuthProvider.um = ium;
-        if (AuthProvider.um  == null){
+        if (AuthProvider.um == null) {
             throw new Exception("No usermanager service available.");
         }
 
         List<String> roles = new ArrayList<String>(1);
         roles.add(UserLevel.SYSTEMADMIN.toString());
-        AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles));
-
-        try {
-            PEM = IOUtils.toString(privateKeyFileInputStream);
-        } catch (IOException e) {
-            logger.error("Error reading RSA key from file.");
-            throw new IllegalStateException("Error reading RSA key from file.");
-        }
+        AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); //FIXME hardcoded auth
+        pem = pemCertificate;
     }
+
     @Override
-    public boolean authenticated(String username, String password)  throws Exception {
-        if (AuthProvider.um  == null){
+    public boolean authenticated(String username, String password) throws Exception {
+        if (AuthProvider.um == null) {
             throw new Exception("No usermanager service available.");
         }
-        AuthResultEnum authResult = AuthProvider.um.authenticate(username,password);
-        if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){
-            return true;
-        }
-        return false;
+        AuthResultEnum authResult = AuthProvider.um.authenticate(username, password);
+        return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC);
     }
 
     @Override
-    public char[] getPEMAsCharArray() throws Exception {
-        if (null == PEM){
-            logger.error("Missing RSA key string.");
-            throw new Exception("Missing RSA key.");
-        }
-        return PEM.toCharArray();
+    public char[] getPEMAsCharArray() {
+        return pem.toCharArray();
     }
 
     @Override
@@ -76,6 +60,4 @@ public class AuthProvider implements AuthProviderInterface {
     public void addUserManagerService(IUserManager userManagerService) {
         AuthProvider.um = userManagerService;
     }
-
-
 }
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java
new file mode 100644 (file)
index 0000000..73886c4
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 org.apache.commons.io.FileUtils;
+import org.bouncycastle.openssl.PEMWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+
+public class PEMGenerator {
+    private static final Logger logger = LoggerFactory.getLogger(PEMGenerator.class);
+    private static final int KEY_SIZE = 4096;
+
+    public static String generateTo(File privateFile) throws Exception {
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        SecureRandom sr = new SecureRandom();
+        keyGen.initialize(KEY_SIZE, sr);
+        KeyPair keypair = keyGen.generateKeyPair();
+        logger.info("Generating private key to {}", privateFile.getAbsolutePath());
+        String privatePEM = toString(keypair.getPrivate());
+        FileUtils.write(privateFile, privatePEM);
+        return privatePEM;
+    }
+
+    private static String toString(Key key) throws IOException {
+        try (StringWriter writer = new StringWriter()) {
+            try (PEMWriter pemWriter = new PEMWriter(writer)) {
+                pemWriter.writeObject(key);
+            }
+            return writer.toString();
+        }
+    }
+}
@@ -5,13 +5,13 @@
  * 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;
+package org.opendaylight.controller.netconf.ssh.osgi;
 
 import com.google.common.base.Optional;
-import java.io.FileInputStream;
-import java.net.InetSocketAddress;
+import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.opendaylight.controller.usermanager.IUserManager;
 import org.osgi.framework.BundleActivator;
@@ -22,6 +22,11 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
 /**
  * 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
@@ -60,7 +65,7 @@ public class NetconfSSHActivator implements BundleActivator{
         @Override
         public void removedService(ServiceReference<IUserManager> reference, IUserManager service) {
             logger.trace("Removing service {} from netconf SSH. " +
-                    "SSH won't authenticate users until IUserManeger service will be started.", reference);
+                    "SSH won't authenticate users until IUserManager service will be started.", reference);
             removeUserManagerService();
         }
     };
@@ -87,15 +92,27 @@ public class NetconfSSHActivator implements BundleActivator{
 
         if (sshSocketAddressOptional.isPresent()){
             String path = NetconfConfigUtil.getPrivateKeyPath(context);
-            path = path.replace("\\", "/");
+            path = path.replace("\\", "/");  // FIXME: shouldn't this convert lines to system dependent path separator?
             if (path.equals("")){
                 throw new Exception("Missing netconf.ssh.pk.path key in configuration file.");
             }
 
-            try (FileInputStream fis = new FileInputStream(path)){
-                AuthProvider authProvider = new AuthProvider(iUserManager,fis);
-                this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
+            File privateKeyFile = new File(path);
+            String privateKeyPEMString;
+            if (privateKeyFile.exists() == false) {
+                // generate & save to file
+                privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
+            } else {
+                // read from file
+                try (FileInputStream fis = new FileInputStream(path)) {
+                    privateKeyPEMString = IOUtils.toString(fis);
+                } catch (IOException e) {
+                    logger.error("Error reading RSA key from file '{}'", path);
+                    throw new IllegalStateException("Error reading RSA key from file " + path);
+                }
             }
+            AuthProvider authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
+            this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
 
             Thread serverThread = new  Thread(server,"netconf SSH server thread");
             serverThread.setDaemon(true);
index e07c7ed..ce26910 100644 (file)
@@ -8,16 +8,6 @@
 package org.opendaylight.controller.netconf.ssh.threads;
 
 
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import ch.ethz.ssh2.AuthenticationResult;
 import ch.ethz.ssh2.PtySettings;
 import ch.ethz.ssh2.ServerAuthenticationCallback;
@@ -26,10 +16,18 @@ import ch.ethz.ssh2.ServerConnectionCallback;
 import ch.ethz.ssh2.ServerSession;
 import ch.ethz.ssh2.ServerSessionCallback;
 import ch.ethz.ssh2.SimpleServerSessionCallback;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.concurrent.ThreadSafe;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
 
 @ThreadSafe
 public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback {
-    private static final Logger logger =  LoggerFactory.getLogger(SocketThread.class);
+    private static final Logger logger = LoggerFactory.getLogger(SocketThread.class);
 
     private final Socket socket;
     private final InetSocketAddress clientAddress;
@@ -43,11 +41,12 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
     public static void start(Socket socket,
                              InetSocketAddress clientAddress,
                              long sessionId,
-                             AuthProvider authProvider) throws IOException{
-        Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId,authProvider));
+                             AuthProvider authProvider) throws IOException {
+        Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket, clientAddress, sessionId, authProvider));
         netconf_ssh_socket_thread.setDaemon(true);
         netconf_ssh_socket_thread.start();
     }
+
     private SocketThread(Socket socket,
                          InetSocketAddress clientAddress,
                          long sessionId,
@@ -56,7 +55,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
         this.socket = socket;
         this.clientAddress = clientAddress;
         this.sessionId = sessionId;
-        this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/","");
+        this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/", "");
         this.authProvider = authProvider;
 
     }
@@ -65,7 +64,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
     public void run() {
         conn = new ServerConnection(socket);
         try {
-            conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf");
+            conn.setPEMHostKey(authProvider.getPEMAsCharArray(), "netconf");
         } catch (Exception e) {
             logger.debug("Server authentication setup failed.");
         }
@@ -74,24 +73,21 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
         try {
             conn.connect();
         } catch (IOException e) {
-            logger.error("SocketThread error ",e);
+            logger.error("SocketThread error ", e);
         }
     }
+
     @Override
-    public ServerSessionCallback acceptSession(final ServerSession session)
-    {
-        SimpleServerSessionCallback cb = new SimpleServerSessionCallback()
-        {
+    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 Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException {
+                return new Runnable() {
                     @Override
-                    public void run()
-                    {
-                        if (subsystem.equals("netconf")){
+                    public void run() {
+                        if (subsystem.equals("netconf")) {
                             IOThread netconf_ssh_input = null;
-                            IOThread  netconf_ssh_output = null;
+                            IOThread netconf_ssh_output = null;
                             try {
                                 String hostName = clientAddress.getHostName();
                                 int portNumber = clientAddress.getPort();
@@ -99,13 +95,13 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
                                 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 = 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");
-                                final String customHeader = "["+currentUser+";"+remoteAddressWithPort+";ssh;;;;;;]\n";
-                                netconf_ssh_output = new IOThread(ss.getStdout(),echoSocket.getOutputStream(),"output_thread_"+sessionId,ss,conn,customHeader);
+                                final String customHeader = "[" + currentUser + ";" + remoteAddressWithPort + ";ssh;;;;;;]\n";
+                                netconf_ssh_output = new IOThread(ss.getStdout(), echoSocket.getOutputStream(), "output_thread_" + sessionId, ss, conn, customHeader);
                                 netconf_ssh_output.setDaemon(false);
                                 netconf_ssh_output.start();
 
@@ -113,56 +109,57 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
                                 logger.error("SSH bridge could not create echo socket: {}", t.getMessage(), t);
 
                                 try {
-                                    if (netconf_ssh_input!=null){
+                                    if (netconf_ssh_input != null) {
                                         netconf_ssh_input.join();
                                     }
                                 } catch (InterruptedException e) {
                                     Thread.currentThread().interrupt();
-                                   logger.error("netconf_ssh_input join error ",e);
+                                    logger.error("netconf_ssh_input join error ", e);
                                 }
 
                                 try {
-                                    if (netconf_ssh_output!=null){
+                                    if (netconf_ssh_output != null) {
                                         netconf_ssh_output.join();
                                     }
                                 } catch (InterruptedException e) {
                                     Thread.currentThread().interrupt();
-                                    logger.error("netconf_ssh_output join error ",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);
-                            }
+                            String reason = "Only netconf subsystem is supported, requested:" + subsystem;
+                            closeSession(ss, reason);
                         }
                     }
                 };
             }
+
+            public void closeSession(ServerSession ss, String reason) {
+                logger.trace("Closing session - {}", reason);
+                try {
+                    ss.getStdin().write(reason.getBytes());
+                } catch (IOException e) {
+                    logger.debug("Exception while closing session", e);
+                }
+                ss.close();
+            }
+
             @Override
-            public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException
-            {
-                return new Runnable()
-                {
+            public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException {
+                return new Runnable() {
                     @Override
-                    public void run()
-                    {
-                        //noop
+                    public void run() {
+                        closeSession(ss, "PTY request not supported");
                     }
                 };
             }
 
             @Override
-            public Runnable requestShell(final ServerSession ss) throws IOException
-            {
-                return new Runnable()
-                {
+            public Runnable requestShell(final ServerSession ss) throws IOException {
+                return new Runnable() {
                     @Override
-                    public void run()
-                    {
-                        //noop
+                    public void run() {
+                        closeSession(ss, "Shell not supported");
                     }
                 };
             }
@@ -172,35 +169,31 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
     }
 
     @Override
-    public String initAuthentication(ServerConnection sc)
-    {
-        logger.trace("Established connection with host {}",remoteAddressWithPort);
-        return "Established connection with host "+remoteAddressWithPort+"\r\n";
+    public String initAuthentication(ServerConnection sc) {
+        logger.trace("Established connection with host {}", remoteAddressWithPort);
+        return "Established connection with host " + remoteAddressWithPort + "\r\n";
     }
 
     @Override
-    public String[] getRemainingAuthMethods(ServerConnection sc)
-    {
-        return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD };
+    public String[] getRemainingAuthMethods(ServerConnection sc) {
+        return new String[]{ServerAuthenticationCallback.METHOD_PASSWORD};
     }
 
     @Override
-    public AuthenticationResult authenticateWithNone(ServerConnection sc, String username)
-    {
+    public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) {
         return AuthenticationResult.FAILURE;
     }
 
     @Override
-    public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
-    {
+    public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) {
 
         try {
-            if (authProvider.authenticated(username,password)){
+            if (authProvider.authenticated(username, password)) {
                 currentUser = username;
-                logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
+                logger.trace("user {}@{} authenticated", currentUser, remoteAddressWithPort);
                 return AuthenticationResult.SUCCESS;
             }
-        } catch (Exception e){
+        } catch (Exception e) {
             logger.warn("Authentication failed due to :" + e.getLocalizedMessage());
         }
         return AuthenticationResult.FAILURE;
@@ -208,8 +201,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
 
     @Override
     public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm,
-            byte[] publickey, byte[] signature)
-    {
+                                                          byte[] publickey, byte[] signature) {
         return AuthenticationResult.FAILURE;
     }
 
diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java
new file mode 100644 (file)
index 0000000..298f91c
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.UserConfig;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+
+// This test is intended to be verified using ssh
+@Ignore
+public class KeyGeneratorTest {
+
+    @Mock
+    private IUserManager iUserManager;
+    File tempFile;
+
+    @Before
+    public void setUp() throws IOException {
+        MockitoAnnotations.initMocks(this);
+        doReturn(null).when(iUserManager).addLocalUser(any(UserConfig.class));
+        tempFile = File.createTempFile("odltest", ".tmp");
+        tempFile.deleteOnExit();
+    }
+
+    @After
+    public void tearDown() {
+        assertTrue(tempFile.delete());
+    }
+
+    @Test
+    public void test() throws Exception {
+        String pem = PEMGenerator.generateTo(tempFile);
+
+        AuthProvider authProvider = new AuthProvider(iUserManager, pem);
+        InetSocketAddress inetSocketAddress = new InetSocketAddress(Inet4Address.getLoopbackAddress().getHostAddress(), 8383);
+        NetconfSSHServer server = NetconfSSHServer.start(1830, inetSocketAddress, authProvider);
+
+        Thread serverThread = new  Thread(server,"netconf SSH server thread");
+        serverThread.start();
+        serverThread.join();
+    }
+}
index 91783ff..663a0b4 100644 (file)
@@ -8,15 +8,17 @@
 package org.opendaylight.controller.netconf;
 
 import ch.ethz.ssh2.Connection;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
 import junit.framework.Assert;
+import org.apache.commons.io.IOUtils;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+
 
 public class SSHServerTest {
 
@@ -34,8 +36,11 @@ public class SSHServerTest {
     public void startSSHServer() throws Exception{
         logger.info("Creating SSH server");
         StubUserManager um = new StubUserManager(USER,PASSWORD);
-        InputStream is = getClass().getResourceAsStream("/RSA.pk");
-        AuthProvider ap = new AuthProvider(um, is);
+        String pem;
+        try(InputStream is = getClass().getResourceAsStream("/RSA.pk")) {
+            pem = IOUtils.toString(is);
+        }
+        AuthProvider ap = new AuthProvider(um, pem);
         NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress,ap);
         sshServerThread = new Thread(server);
         sshServerThread.setDaemon(true);
index 2e3100f..6b12a19 100644 (file)
@@ -8,8 +8,6 @@
 
 package org.opendaylight.controller.netconf.util.mapping;
 
-import java.util.Map;
-
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
@@ -22,6 +20,8 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
+import java.util.Map;
+
 public abstract class AbstractNetconfOperation implements NetconfOperation {
     private final String netconfSessionIdForReporting;
 
@@ -118,8 +118,12 @@ public abstract class AbstractNetconfOperation implements NetconfOperation {
 
     @Override
     public String toString() {
-        final StringBuffer sb = new StringBuffer("AbstractConfigNetconfOperation{");
-        sb.append("name=").append(getOperationName());
+        final StringBuffer sb = new StringBuffer(getClass().getName());
+        try {
+            sb.append("{name=").append(getOperationName());
+        } catch(UnsupportedOperationException e) {
+            // no problem
+        }
         sb.append(", namespace=").append(getOperationNamespace());
         sb.append(", session=").append(netconfSessionIdForReporting);
         sb.append('}');
index 586366f..2be64a8 100644 (file)
                 <artifactId>config-persister-api</artifactId>
                 <version>${config.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.opendaylight.controller</groupId>
-                <artifactId>config-persister-file-adapter</artifactId>
-                <version>${config.version}</version>
-            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>netconf-client</artifactId>
index 6582d8c..ae84a72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright IBM Corporation, 2013.  All rights reserved.
+ * Copyright IBM Corporation and others, 2013.  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,
@@ -64,6 +64,12 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable {
     @XmlElement (name="tenant_id")
     String tenantID;
 
+    @XmlElement (name="ipv6_address_mode", nillable=true)
+    String ipV6AddressMode;
+
+    @XmlElement (name="ipv6_ra_mode", nillable=true)
+    String ipV6RaMode;
+
     /* stores the OpenStackPorts associated with an instance
      * used to determine if that instance can be deleted.
      */
@@ -170,6 +176,14 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable {
         this.tenantID = tenantID;
     }
 
+    public String getIpV6AddressMode() { return ipV6AddressMode; }
+
+    public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; }
+
+    public String getIpV6RaMode() { return ipV6RaMode; }
+
+    public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; }
+
     /**
      * This method copies selected fields from the object and returns them
      * as a new object, suitable for marshaling.
@@ -224,6 +238,12 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable {
             if (s.equals("tenant_id")) {
                 ans.setTenantID(this.getTenantID());
             }
+            if (s.equals("ipv6_address_mode")) {
+                ans.setIpV6AddressMode(this.getIpV6AddressMode());
+            }
+            if (s.equals("ipv6_ra_mode")) {
+                ans.setIpV6RaMode(this.getIpV6RaMode());
+            }
         }
         return ans;
     }
@@ -444,6 +464,7 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable {
                 + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers="
                 + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes
                 + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID + ", myPorts=" + myPorts
-                + ", gatewayIPAssigned=" + gatewayIPAssigned + "]";
+                + ", gatewayIPAssigned=" + gatewayIPAssigned + ", ipv6AddressMode=" + ipV6AddressMode
+                + ", ipv6RaMode=" + ipV6RaMode + "]";
     }
 }
index 224fcb5..f397eb3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright IBM Corporation, 2013.  All rights reserved.
+ * Copyright IBM Corporation and others, 2013.  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,
@@ -87,6 +87,8 @@ public class NeutronSubnetsNorthbound {
             @QueryParam("gateway_ip") String queryGatewayIP,
             @QueryParam("enable_dhcp") String queryEnableDHCP,
             @QueryParam("tenant_id") String queryTenantID,
+            @QueryParam("ipv6_address_mode") String queryIpV6AddressMode,
+            @QueryParam("ipv6_ra_mode") String queryIpV6RaMode,
             // pagination
             @QueryParam("limit") String limit,
             @QueryParam("marker") String marker,
@@ -110,7 +112,9 @@ public class NeutronSubnetsNorthbound {
                     (queryCIDR == null || queryCIDR.equals(oSS.getCidr())) &&
                     (queryGatewayIP == null || queryGatewayIP.equals(oSS.getGatewayIP())) &&
                     (queryEnableDHCP == null || queryEnableDHCP.equals(oSS.getEnableDHCP())) &&
-                    (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {
+                    (queryTenantID == null || queryTenantID.equals(oSS.getTenantID())) &&
+                    (queryIpV6AddressMode == null || queryIpV6AddressMode.equals(oSS.getIpV6AddressMode())) &&
+                    (queryIpV6RaMode == null || queryIpV6RaMode.equals(oSS.getIpV6RaMode()))){
                 if (fields.size() > 0) {
                     ans.add(extractFields(oSS,fields));
                 } else {

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.