<version>1.4.2-SNAPSHOT</version>
<type>zip</type>
</dependency>
+ <!-- Bundle dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>dummy-console</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal.connection</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal.connection.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal.networkconfiguration</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal.networkconfiguration.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.services</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.services-implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>clustering.stub</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>configuration</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>configuration.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>logging.bridge</artifactId>
+ </dependency>
</dependencies>
<build>
<resources>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
-
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>dummy-console</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>karaf-tomcat-security</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>ganymed</artifactId>
+ </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
-
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
-
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
-
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
</dependency>
-
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-base</artifactId>
</dependency>
-
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
-
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
</dependency>
-
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>ganymed</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </dependency>
<dependency>
<groupId>org.openexi</groupId>
<artifactId>nagasena</artifactId>
<feature version='${project.version}'>odl-netconf-util</feature>
<bundle>mvn:org.opendaylight.controller/netconf-netty-util/${project.version}</bundle>
<bundle>mvn:org.opendaylight.controller.thirdparty/ganymed/${ganymed.version}</bundle>
+ <bundle>mvn:org.apache.sshd/sshd-core/${sshd-core.version}</bundle>
<bundle>mvn:org.openexi/nagasena/${exi.nagasena.version}</bundle>
<bundle>mvn:io.netty/netty-codec/${netty.version}</bundle>
<bundle>mvn:io.netty/netty-handler/${netty.version}</bundle>
<bundle>mvn:org.opendaylight.controller/netconf-monitoring/${project.version}</bundle>
</feature>
-</features>
\ No newline at end of file
+</features>
<version>1.4.2-SNAPSHOT</version>
<type>zip</type>
</dependency>
+ <!-- Bundle Dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>appauth</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>arphandler</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>bundlescanner</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>bundlescanner.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>configuration</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>configuration.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>connectionmanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>connectionmanager.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>connectionmanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager.shell</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>controllermanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>devices.web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>flowprogrammer.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>flows.web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>routing.dijkstra_implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwarding.staticrouting</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwarding.staticrouting.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwardingrulesmanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwardingrulesmanager.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker.shell</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>httpservice-bridge</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>jolokia-bridge</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>logging.bridge</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>networkconfig.bridgedomain.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>networkconfig.neutron</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>networkconfig.neutron.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>networkconfig.neutron.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>osgi-brandfragment.web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>samples.loadbalancer</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>samples.loadbalancer.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>samples.simpleforwarding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>security</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>statistics.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>statisticsmanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>statisticsmanager.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>subnets.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topology.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topology.web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topologymanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topologymanager.shell</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>troubleshoot.web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>usermanager</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>usermanager.implementation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>usermanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>net.sf.jung2</artifactId>
+ </dependency>
</dependencies>
<build>
<resources>
<bundle>mvn:org.opendaylight.controller/hosttracker.implementation/${hosttracker.implementation.version}</bundle>
<bundle>mvn:org.opendaylight.controller/hosttracker.shell/${hosttracker.shell.version}</bundle>
- <bundle>mvn:org.opendaylight.controller/forwarding.staticrouting</bundle>
+ <bundle>mvn:org.opendaylight.controller/forwarding.staticrouting/${forwarding.staticrouting}</bundle>
<bundle>mvn:org.opendaylight.controller.thirdparty/net.sf.jung2/2.0.1</bundle>
- <bundle>mvn:org.opendaylight.controller/routing.dijkstra_implementation</bundle>
+ <bundle>mvn:org.opendaylight.controller/routing.dijkstra_implementation/${routing.dijkstra_implementation.version}</bundle>
</feature>
<feature name="odl-adsal-northbound" description="OpenDaylight :: AD-SAL :: Northbound APIs" version="${project.version}">
<bundle>mvn:org.opendaylight.controller/bundlescanner/${bundlescanner.api.version}</bundle>
<bundle>mvn:org.opendaylight.controller/bundlescanner.implementation/${bundlescanner.implementation.version}</bundle>
<bundle>mvn:org.opendaylight.controller/commons.northbound/${northbound.commons.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/connectionmanager.northbound/${connectionmanager.version}</bundle>
<bundle>mvn:org.opendaylight.controller/flowprogrammer.northbound/${flowprogrammer.northbound.version}</bundle>
<bundle>mvn:org.opendaylight.controller/hosttracker.northbound/${hosttracker.northbound.version}</bundle>
<bundle>mvn:org.opendaylight.controller/networkconfig.bridgedomain.northbound/${networkconfig.bridgedomain.northbound.version}</bundle>
--- /dev/null
+<?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>
+
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-configfile-archetype</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ <packaging>maven-archetype</packaging>
+
+
+ <build>
+ <extensions>
+ <extension>
+ <groupId>org.apache.maven.archetype</groupId>
+ <artifactId>archetype-packaging</artifactId>
+ <version>2.2</version>
+ </extension>
+ </extensions>
+
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-archetype-plugin</artifactId>
+ <version>2.2</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <description>Configuration files for md-sal</description>
+
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git/md-sal-config</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git/md-sal-config</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL/md-sal-config</url>
+ </scm>
+
+ <distributionManagement>
+ <repository>
+ <id>opendaylight-release</id>
+ <url>http://nexus.opendaylight.org/content/repositories/opendaylight.release/</url>
+ </repository>
+ <snapshotRepository>
+ <id>opendaylight-snapshot</id>
+ <url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+ </snapshotRepository>
+ <site>
+ <id>website</id>
+ <url>dav:http://nexus.opendaylight.org/content/sites/site/sal-parent</url>
+ </site>
+ </distributionManagement>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<archetype-descriptor xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd" name="md-sal-config"
+ xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <requiredProperties>
+ <requiredProperty key="repoName"/>
+ </requiredProperties>
+ <fileSets>
+ <fileSet filtered="true" encoding="UTF-8">
+ <directory>src/main/resources</directory>
+ <includes>
+ <include>**/*.xml</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</archetype-descriptor>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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
+--><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>
+ <!--
+ Necessary TODO: Hookup your parent pom here, else you will not get necessary versions,
+ maven repos etc. If you run this archetype in a subdirectory of your project, it
+ will pick the pom.xml from the parent directory as the parent pom, which may or may
+ not be correct.
+ -->
+ <artifactId>${artifactId}</artifactId>
+ <groupId>${groupId}</groupId>
+ <description>Configuration files for md-sal</description>
+ <!-- Optional TODO: Uncomment version if you are not using a parent pom.xml
+ <version>${version}</version>
+ -->
+ <packaging>jar</packaging>
+ <properties>
+ <!-- Optional TODO: Rename your configfile to taste -->
+ <configfile>80-configfile.xml</configfile>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/classes/${configfile}</file>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/${repoName}.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/${repoName}.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://git.opendaylight.org/gerrit/gitweb?p=${repoName}.git;a=summary</url>
+ </scm>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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
+-->
+<snapshot>
+ <required-capabilities>
+ <!-- Necessary TODO put your required capabilities here
+
+ Examples:
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&revision=2013-11-19</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup?module=threadgroup&revision=2013-11-07</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:timer?module=netty-timer&revision=2013-11-19</capability>
+ -->
+ </required-capabilities>
+ <configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <!-- Optional TODO: Add your modules definitions here
+ Examples:
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup">netty:netty-threadgroup-fixed</type>
+ <name>global-boss-group</name>
+ </module>
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup">netty:netty-threadgroup-fixed</type>
+ <name>global-worker-group</name>
+ </module>
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:timer">netty:netty-hashed-wheel-timer</type>
+ <name>global-timer</name>
+ </module>
+ <module>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor">netty:netty-global-event-executor</type>
+ <name>singleton</name>
+ </module>
+ -->
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <!-- Optional TODO: Put your service instance definitions here
+ Examples:
+ <service>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-threadgroup</type>
+ <instance>
+ <name>global-boss-group</name>
+ <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-boss-group']</provider>
+ </instance>
+ <instance>
+ <name>global-worker-group</name>
+ <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-worker-group']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-event-executor</type>
+ <instance>
+ <name>global-event-executor</name>
+ <provider>/modules/module[type='netty-global-event-executor'][name='singleton']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-timer</type>
+ <instance>
+ <name>global-timer</name>
+ <provider>/modules/module[type='netty-hashed-wheel-timer'][name='global-timer']</provider>
+ </instance>
+ </service>
+ -->
+ </services>
+ </data>
+
+ </configuration>
+</snapshot>
--- /dev/null
+#Mon Aug 25 05:45:18 CDT 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
+repoName=foo
--- /dev/null
+<?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>
+
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-karaf-distro-archetype</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>maven-archetype</packaging>
+
+ <name>distribution-karaf-archetype</name>
+
+ <build>
+ <extensions>
+ <extension>
+ <groupId>org.apache.maven.archetype</groupId>
+ <artifactId>archetype-packaging</artifactId>
+ <version>2.2</version>
+ </extension>
+ </extensions>
+
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-archetype-plugin</artifactId>
+ <version>2.2</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <url>https://wiki.opendaylight.org/view/CrossProject:Integration_Group/distribution-karaf</url>
+
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+ </scm>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<archetype-descriptor xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
+ xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <requiredProperties>
+ <requiredProperty key="repoName"/>
+ </requiredProperties>
+</archetype-descriptor>
--- /dev/null
+<?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>
+ <!--
+ Necessary TODO: Hookup your parent pom here, else you will not get necessary versions,
+ maven repos etc. If you run this archetype in a subdirectory of your project, it
+ will pick the pom.xml from the parent directory as the parent pom, which may or may
+ not be correct.
+ -->
+ <artifactId>${artifactId}</artifactId>
+ <groupId>${groupId}</groupId>
+ <!-- Optional TODO: Uncomment version if you are not using a parent pom.xml
+ <version>${version}</version>
+ -->
+ <packaging>pom</packaging>
+ <prerequisites>
+ <maven>3.0</maven>
+ </prerequisites>
+ <properties>
+ <!-- Optional TODO: Move these properties to your parent pom and possibly
+ DependencyManagement section of your parent pom -->
+ <branding.version>1.0.0-SNAPSHOT</branding.version>
+ <karaf.resources.version>1.4.2-SNAPSHOT</karaf.resources.version>
+ <karaf.version>3.0.1</karaf.version>
+ </properties>
+
+ <dependencies>
+ <!-- Basic Karaf dependencies -->
+ <dependency>
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>framework</artifactId>
+ <version>${karaf.version}</version>
+ <type>kar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>standard</artifactId>
+ <version>${karaf.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+
+ <!-- ODL Branding -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>karaf.branding</artifactId>
+ <version>${branding.version}</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <!-- ODL Resources needed for karaf -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-karaf-resources</artifactId>
+ <version>${karaf.resources.version}</version>
+ </dependency>
+
+ <!-- Project local feautures -->
+ <!--
+ Necessary TODO put your features here.
+
+ Note: they will need to be <type>xml</xml>
+ and <classifier>features</classifier>.
+
+ Note: they must be <scope>runtime</scope>
+
+ Note: usually you would only need to depend
+ on your own feature file here for your local distro,
+ and possible the features-mdsal for odl-restconf
+ (although, strange situations do exist :) )
+
+ Example:
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-mdsal</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>features-openflowplugin</artifactId>
+ <version>0.0.3-SNAPSHOT</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ -->
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>cleanVersions</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>copy</goal>
+ <goal>unpack</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>commands-generate-help</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.fusesource.scalate</groupId>
+ <artifactId>maven-scalate-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>sitegen</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <versionRange>[0,)</versionRange>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-maven-plugin</artifactId>
+ <version>${karaf.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <bootFeatures>
+ <feature>standard</feature>
+ <!--
+ Optional TODO: Add entries here for the features you want in your local distro
+ Note: odl-restconf is a separate feature from odl-mdsal-broker. If you want
+ restconf, you need to list it here explicitely.
+ Examples:
+ <feature>odl-openflowplugin-flow-services</feature>
+ <feature>odl-restconf</feature>
+ -->
+ <!-- Final TODO: Remove TODO Comments ;) -->
+ </bootFeatures>
+ </configuration>
+ <executions>
+ <execution>
+ <id>process-resources</id>
+ <goals>
+ <goal>install-kars</goal>
+ </goals>
+ <phase>process-resources</phase>
+ </execution>
+ <execution>
+ <id>package</id>
+ <goals>
+ <goal>instance-create-archive</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>copy</id>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <phase>generate-resources</phase>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>karaf.branding</artifactId>
+ <version>${karaf.branding.version}</version>
+ <outputDirectory>target/assembly/lib</outputDirectory>
+ <destFileName>karaf.branding-${branding.version}.jar</destFileName>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ <execution>
+ <id>unpack-karaf-resources</id>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <phase>prepare-package</phase>
+ <configuration>
+ <outputDirectory>${project.build.directory}/assembly</outputDirectory>
+ <groupId>org.opendaylight.controller</groupId>
+ <includeArtifactIds>opendaylight-karaf-resources</includeArtifactIds>
+ <excludes>META-INF\/**</excludes>
+ <excludeTransitive>true</excludeTransitive>
+ <ignorePermissions>false</ignorePermissions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <tasks>
+ <chmod perm="755">
+ <fileset dir="${project.build.directory}/assembly/bin">
+ <include name="karaf" />
+ <include name="instance" />
+ <include name="start"/>
+ <include name="stop"/>
+ <include name="status"/>
+ <include name="client"/>
+ <include name="shell"/>
+ </fileset>
+ </chmod>
+ </tasks>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/${repoName}.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/${repoName}.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://git.opendaylight.org/gerrit/gitweb?p=${repoName}.git;a=summary</url>
+ </scm>
+</project>
--- /dev/null
+#Thu Aug 21 14:44:29 CDT 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
+repoName=foo
--- /dev/null
+<?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>
+
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-karaf-features-archetype</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>maven-archetype</packaging>
+
+ <name>opendaylight-karaf-features-archetype</name>
+
+ <build>
+ <extensions>
+ <extension>
+ <groupId>org.apache.maven.archetype</groupId>
+ <artifactId>archetype-packaging</artifactId>
+ <version>2.2</version>
+ </extension>
+ </extensions>
+
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-archetype-plugin</artifactId>
+ <version>2.2</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git/</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git/</developerConnection>
+ <url>https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=summary</url>
+ </scm>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<archetype-descriptor xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd" name="features-integration"
+ xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <requiredProperties>
+ <requiredProperty key="repoName"/>
+ </requiredProperties>
+ <fileSets>
+ <fileSet filtered="true" encoding="UTF-8">
+ <directory>src/main/resources</directory>
+ <include>**/*.xml</include>
+ </fileSet>
+ </fileSets>
+</archetype-descriptor>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Necessary TODO: Put your copyright here.
+
+ 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
+-->
+<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>
+ <!--
+ Necessary TODO: Hookup your parent pom here, else you will not get necessary versions,
+ maven repos etc. If you run this archetype in a subdirectory of your project, it
+ will pick the pom.xml from the parent directory as the parent pom, which may or may
+ not be correct.
+ -->
+ <artifactId>features-${repoName}</artifactId>
+ <groupId>${groupId}</groupId>
+ <!-- Optional TODO: Uncomment version if you are not using a parent pom.xml
+ <version>${version}</version>
+ -->
+ <packaging>jar</packaging>
+ <properties>
+ <features.file>features.xml</features.file>
+ <!-- Optional TODO: Move these properties to your parent pom and possibly
+ DependencyManagement section of your parent pom -->
+ <branding.version>1.0.0-SNAPSHOT</branding.version>
+ <karaf.resources.version>1.4.2-SNAPSHOT</karaf.resources.version>
+ <karaf.version>3.0.1</karaf.version>
+ <feature.test.version>0.6.2-SNAPSHOT</feature.test.version>
+ <karaf.empty.version>1.4.2-SNAPSHOT</karaf.empty.version>
+ <surefire.version>2.16</surefire.version>
+ </properties>
+ <dependencies>
+ <!--
+ Necessary TODO: Put dependencies on any feature repos
+ you use in your features.xml file.
+
+ Note: they will need to be <type>xml</xml>
+ and <classifier>features</classifier>.
+ One other thing to watch for is to make sure they are
+ <scope>compile</compile>, which they should be by default,
+ but be cautious lest they be at a different scope in a parent pom.
+
+ Examples:
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>features-yangtools</artifactId>
+ <version>0.6.2-SNAPSHOT</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-mdsal</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>features-openflowplugin</artifactId>
+ <version>0.0.3-SNAPSHOT</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ -->
+
+ <!--
+ Necessary TODO: Put dependencies for bundles directly referenced
+ in your features.xml file. For every <bundle> reference in your
+ features.xml file, you need a corresponding dependency here.
+
+ Examples:
+ <dependency>
+ <groupId>${groupId}</groupId>
+ <artifactId>${repoName}-provider</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${groupId}</groupId>
+ <artifactId>${repoName}-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ -->
+
+ <!--
+ Necessary TODO: Put dependencies for configfiles directly referenced
+ in your features.xml file. For every <configfile> reference in your
+ features.xml file, you need a corresponding dependency here.
+
+ Example (presuming here version is coming from the parent pom):
+ <dependency>
+ <groupId>${groupId}</groupId>
+ <artifactId>${repoName}-config</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
+ -->
+
+ <!--
+ Optional TODO: Remove TODO comments.
+ -->
+ <!-- test to validate features.xml -->
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>features-test</artifactId>
+ <version>${feature.test.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <!-- dependency for opendaylight-karaf-empty for use by testing -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>opendaylight-karaf-empty</artifactId>
+ <version>${karaf.empty.version}</version>
+ <type>zip</type>
+ </dependency>
+ <!-- Uncomment this if you get an error : java.lang.NoSuchMethodError: org.slf4j.helpers.MessageFormatter.format(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Lorg/slf4j/helpers/FormattingTuple;
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.7.2</version>
+ </dependency>
+ -->
+
+ </dependencies>
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>filter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>resources</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${project.build.directory}/classes/${features.file}</file>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>
+ <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>
+ <karaf.distro.version>${karaf.empty.version}</karaf.distro.version>
+ </systemPropertyVariables>
+ <dependenciesToScan>
+ <dependency>org.opendaylight.yangtools:features-test</dependency>
+ </dependenciesToScan>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/${repoName}.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/${repoName}.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://git.opendaylight.org/gerrit/gitweb?p=${repoName}.git;a=summary</url>
+ </scm>
+</project>
--- /dev/null
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Necessary TODO: Put your copyright statement here
+
+ 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
+-->
+<features name="odl-${repoName}-${symbol_dollar}{project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+ <!--
+ Necessary TODO: Please read the features guidelines:
+ https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Feature_Best_Practices
+ -->
+ <!--
+ Necessary TODO: Add repo entries for the repositories of features you refer to
+ in this feature file but do not define here.
+ Examples:
+ <repository>mvn:org.opendaylight.yangtools/features-yangtools/0.6.2-SNAPSHOT/xml/features</repository>
+ <repository>mvn:org.opendaylight.controller/features-mdsal/1.1-SNAPSHOT/xml/features</repository>
+ <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.0.3-SNAPSHOT/xml/features</repository>
+ -->
+ <feature name='odl-${repoName}-all' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${repoName} :: All'>
+ <!--
+ Necessary TODO:
+ List all of the user consumable features you define in this feature file here.
+ Generally you would *not* list individual bundles here, but only features defined in *this* file.
+ It is useful to list them in the same order they occur in the file.
+
+ Examples:
+ <feature version='${symbol_dollar}{project.version}'>odl-${repoName}-provider</feature>
+ <feature version='${symbol_dollar}{project.version}'>odl-${repoName}-model</feature>
+ -->
+ </feature>
+ <!--
+ Necessary TODO: Define your features. It is useful to list then in order of dependency. So if A depends on B, list A first.
+ When naming your features please be mindful of the guidelines:
+ https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines
+ Particularly:
+ a) Prefixing names with 'odl-': https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Feature_Naming
+ b) Descriptions: https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Description
+ c) Avoid start-levels: https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Avoid_start-levels
+
+ It's also nice to list inside a feature, first the features it needs, then the bundles it needs, then the configfiles.
+ Examples:
+
+ * Basic MD-SAL Provider
+ <feature name='odl-${repoName}-provider' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${repoName} :: Provider '>
+ <feature version='1.1-SNAPSHOT'>odl-mdsal-broker</feature>
+ <feature version='${symbol_dollar}{project.version}'>odl-${repoName}-model</feature>
+ <bundle>mvn:${groupId}/${repoName}-provider/${symbol_dollar}{project.version}</bundle>
+ ... whatever other bundles you need
+ </feature>
+
+ * Basic MD-SAL Model feature
+ <feature name='odl-${repoName}-model' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${repoName} :: Model'>
+ <feature version='0.6.2-SNAPSHOT'>odl-yangtools-binding</feature>
+ <feature version='0.6.2-SNAPSHOT'>odl-yangtools-models</feature>
+ <bundle>mvn:${groupId}/${repoName}-model/${symbol_dollar}{project.version}</bundle>
+ ... whatever other bundles you need
+ </feature>
+
+ * Config Subsystem example - the config file is your config subsystem configuration
+ <feature name='odl-${repoName}-provider' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${repoName} :: Provider'>
+ <feature version='1.1-SNAPSHOT'>odl-mdsal-broker</feature>
+ <bundle>mvn:${groupId}/${repoName}-provider/${symbol_dollar}{project.version}</bundle>
+ <configfile finalname="etc/opendaylight/karaf/80-${repoName}.xml">mvn:${groupId}/${repoName}-config/${symbol_dollar}{project.version}/xml/config</configfile>
+ ... whatever other bundles you need
+ </feature>
+
+ * Basic MD-SAL Provider that uses openflowplugin-flow-services (which brings along odl-mdsal-broker)
+ <feature name='odl-${repoName}-provider' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${repoName} :: Provider'>
+ <feature version='0.0.3-SNAPSHOT'>odl-openflowplugin-flow-services</feature>
+ <bundle>mvn:${groupId}/${repoName}-provider/${symbol_dollar}{project.version}</bundle>
+ ... whatever other bundles you need
+ </feature>
+
+ -->
+ <!-- Optional TODO: Remove TODO Comments -->
+
+</features>
--- /dev/null
+#Thu Aug 21 23:46:25 CDT 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
+repoName=foo
</prerequisites>
<parent>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>commons.parent</artifactId>
- <version>1.0.1-SNAPSHOT</version>
- <relativePath>../commons/parent</relativePath>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.2-SNAPSHOT</version>
+ <relativePath>../commons/opendaylight</relativePath>
</parent>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
</distributionManagement>
<modules>
<module>odl-model-project</module>
+ <module>opendaylight-configfile-archetype</module>
+ <module>opendaylight-karaf-distro-archetype</module>
+ <module>opendaylight-karaf-features</module>
</modules>
</project>
<yang-ext.version>2013.09.07.4-SNAPSHOT</yang-ext.version>
<yang-jmx-generator.version>1.0.0-SNAPSHOT</yang-jmx-generator.version>
<yangtools.version>0.6.2-SNAPSHOT</yangtools.version>
+ <sshd-core.version>0.12.0</sshd-core.version>
</properties>
<dependencyManagement>
<artifactId>netconf-netty-util</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ <version>${sshd-core.version}</version>
+ </dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<artifactId>hosttracker.northbound</artifactId>
<version>${hosttracker.northbound.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker.shell</artifactId>
+ <version>${hosttracker.shell.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>hosttracker_new</artifactId>
<artifactId>logging.bridge</artifactId>
<version>${logging.bridge.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>dummy-console</artifactId>
+ <version>${dummy-console.version}</version>
+ </dependency>
<!-- Netconf -->
<dependency>
<artifactId>security</artifactId>
<version>${security.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>karaf-tomcat-security</artifactId>
+ <version>${karaf.security.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>topologymanager</artifactId>
<version>${topologymanager.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topologymanager.shell</artifactId>
+ <version>${topologymanager.shell.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>troubleshoot.web</artifactId>
# Extra packages to import from the boot class loader
org.osgi.framework.system.packages.extra=org.apache.karaf.branding,sun.reflect,sun.reflect.misc,sun.misc,sun.nio.ch
+# Override the config.properties to remove
+# ${services-${karaf.framework}}
+# This is to work around:
+# https://issues.apache.org/jira/browse/KARAF-3092
+# Which should be fixed in karaf 3.0.2
+# Which is not as of today (2014-08-24) released.
+# Since it is biting folks, we need to fix it here
+# Please remove this when we shift to karaf 3.0.2
+org.osgi.framework.system.capabilities= \
+ ${eecap-${java.specification.version}}, \
+ service-reference;effective:=active;objectClass=org.osgi.service.packageadmin.PackageAdmin, \
+ service-reference;effective:=active;objectClass=org.osgi.service.startlevel.StartLevel, \
+ service-reference;effective:=active;objectClass=org.osgi.service.url.URLHandlers
+
# https://bugs.eclipse.org/bugs/show_bug.cgi?id=325578
# Extend the framework to avoid the resources to be presented with
# a URL of type bundleresource: but to be presented as file:
#Hosttracker hostsdb key scheme setting
hosttracker.keyscheme=IP
+
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>ganymed</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>binding-generator-api</artifactId>
<artifactId>scala-library</artifactId>
</dependency>
- <!-- Test Dependencies -->
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-slf4j_${scala.version}</artifactId>
+ </dependency>
+
+
+ <!-- Test Dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<includes>
- <include>org.opendaylight.controller.*</include>
+ <include>org/opendaylight/controller/cluster/**/*</include>
</includes>
+ <excludes>
+ <exclude>org/opendaylight/controller/cluster/raft/protobuff/**/*</exclude>
+ <exclude>org/opendaylight/controller/cluster/example/**/*</exclude>
+ </excludes>
<check>false</check>
</configuration>
<executions>
} else if (message instanceof FindLeader) {
getSender().tell(
- new FindLeaderReply(
- context.getPeerAddress(currentBehavior.getLeaderId())),
+ new FindLeaderReply(getLeaderAddress()),
getSelf()
);
// TODO: Handle failure in saving the snapshot
- } else if (message instanceof FindLeader){
-
- getSender().tell(new FindLeaderReply(
- context.getPeerAddress(currentBehavior.getLeaderId())),
- getSelf());
-
} else if (message instanceof AddRaftPeer){
// FIXME : Do not add raft peers like this.
* @return A reference to the leader if known, null otherwise
*/
protected ActorSelection getLeader(){
- String leaderId = currentBehavior.getLeaderId();
- if (leaderId == null) {
- return null;
- }
- String peerAddress = context.getPeerAddress(leaderId);
- LOG.debug("getLeader leaderId = " + leaderId + " peerAddress = "
- + peerAddress);
+ String leaderAddress = getLeaderAddress();
- if(peerAddress == null){
- return null;
- }
- return context.actorSelection(peerAddress);
+ return context.actorSelection(leaderAddress);
}
/**
deleteMessages(sequenceNumber);
}
+ private String getLeaderAddress(){
+ if(isLeader()){
+ return getSelf().path().toString();
+ }
+ String leaderId = currentBehavior.getLeaderId();
+ if (leaderId == null) {
+ return null;
+ }
+ String peerAddress = context.getPeerAddress(leaderId);
+ LOG.debug("getLeaderAddress leaderId = " + leaderId + " peerAddress = "
+ + peerAddress);
+
+ return peerAddress;
+ }
+
private class ReplicatedLogImpl extends AbstractReplicatedLogImpl {
package org.opendaylight.controller.cluster.raft.client.messages;
-public class FindLeader {
+import java.io.Serializable;
+
+public class FindLeader implements Serializable{
}
package org.opendaylight.controller.cluster.raft.client.messages;
-public class FindLeaderReply {
+import java.io.Serializable;
+
+public class FindLeaderReply implements Serializable {
private final String leaderActor;
public FindLeaderReply(String leaderActor) {
import akka.actor.ActorSystem;
import akka.testkit.JavaTestKit;
+import org.apache.commons.io.FileUtils;
import org.junit.AfterClass;
import org.junit.BeforeClass;
+import java.io.File;
+import java.io.IOException;
+
public abstract class AbstractActorTest {
private static ActorSystem system;
@BeforeClass
- public static void setUpClass() {
+ public static void setUpClass() throws Exception{
+ deleteJournal();
System.setProperty("shard.persistent", "false");
system = ActorSystem.create("test");
}
@AfterClass
- public static void tearDownClass() {
+ public static void tearDownClass() throws Exception{
+ deleteJournal();
JavaTestKit.shutdownActorSystem(system);
system = null;
}
return system;
}
+ protected static void deleteJournal() throws IOException {
+ File journal = new File("journal");
+
+ if(journal.exists()) {
+ FileUtils.deleteDirectory(journal);
+ }
+ }
+
}
--- /dev/null
+package org.opendaylight.controller.cluster.raft;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import akka.event.Logging;
+import akka.japi.Creator;
+import akka.testkit.JavaTestKit;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
+import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
+
+import java.util.Collections;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class RaftActorTest extends AbstractActorTest {
+
+
+ public static class MockRaftActor extends RaftActor {
+
+ public MockRaftActor(String id,
+ Map<String, String> peerAddresses) {
+ super(id, peerAddresses);
+ }
+
+ public static Props props(final String id, final Map<String, String> peerAddresses){
+ return Props.create(new Creator<MockRaftActor>(){
+
+ @Override public MockRaftActor create() throws Exception {
+ return new MockRaftActor(id, peerAddresses);
+ }
+ });
+ }
+
+ @Override protected void applyState(ActorRef clientActor,
+ String identifier,
+ Object data) {
+ }
+
+ @Override protected Object createSnapshot() {
+ throw new UnsupportedOperationException("createSnapshot");
+ }
+
+ @Override protected void applySnapshot(Object snapshot) {
+ throw new UnsupportedOperationException("applySnapshot");
+ }
+
+ @Override protected void onStateChanged() {
+ }
+
+ @Override public String persistenceId() {
+ return this.getId();
+ }
+
+ }
+
+
+ private static class RaftActorTestKit extends JavaTestKit {
+ private final ActorRef raftActor;
+
+ public RaftActorTestKit(ActorSystem actorSystem, String actorName) {
+ super(actorSystem);
+
+ raftActor = this.getSystem()
+ .actorOf(MockRaftActor.props(actorName,
+ Collections.EMPTY_MAP), actorName);
+
+ }
+
+
+ public boolean waitForStartup(){
+ // Wait for a specific log message to show up
+ return
+ new JavaTestKit.EventFilter<Boolean>(Logging.Info.class
+ ) {
+ protected Boolean run() {
+ return true;
+ }
+ }.from(raftActor.path().toString())
+ .message("Switching from state Candidate to Leader")
+ .occurrences(1).exec();
+
+
+ }
+
+ public void findLeader(final String expectedLeader){
+
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ raftActor.tell(new FindLeader(), getRef());
+
+ String s = new ExpectMsg<String>(duration("1 seconds"),
+ "findLeader") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof FindLeaderReply) {
+ return ((FindLeaderReply) in).getLeaderActor();
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get();// this extracts the received message
+
+ assertEquals(expectedLeader, s);
+
+ }
+
+
+ };
+ }
+
+ public ActorRef getRaftActor() {
+ return raftActor;
+ }
+
+ }
+
+
+ @Test
+ public void testConstruction() {
+ boolean started = new RaftActorTestKit(getSystem(), "testConstruction").waitForStartup();
+ assertEquals(true, started);
+ }
+
+ @Test
+ public void testFindLeaderWhenLeaderIsSelf(){
+ RaftActorTestKit kit = new RaftActorTestKit(getSystem(), "testFindLeader");
+ kit.waitForStartup();
+ kit.findLeader(kit.getRaftActor().path().toString());
+ }
+
+
+}
akka {
-
loglevel = "DEBUG"
+ loggers = ["akka.testkit.TestEventListener", "akka.event.slf4j.Slf4jLogger"]
actor {
# enable to test serialization only.
}
serialization-bindings {
+ "org.opendaylight.controller.cluster.raft.client.messages.FindLeader" = java
"org.opendaylight.controller.cluster.raft.ReplicatedLogImplEntry" = java
"com.google.protobuf.Message" = proto
"com.google.protobuf.GeneratedMessage" = proto
mavenBundle(CONTROLLER, "netconf-client").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-util").versionAsInProject(), //
mavenBundle(CONTROLLER, "netconf-netty-util").versionAsInProject(), //
+ mavenBundle("org.apache.sshd", "sshd-core").versionAsInProject(), //
mavenBundle("org.openexi", "nagasena").versionAsInProject(), //
mavenBundle("org.openexi", "nagasena-rta").versionAsInProject(), //
mavenBundle(CONTROLLER + ".thirdparty", "ganymed").versionAsInProject(), //
String parentPath = "";
if(id != null){
- parentPath = PathUtils.getParentPath(id.toString());
+ parentPath = PathUtils.getParentPath(PathUtils.toString(id));
}
@Override
public void visitNode(int level, String parentPath, NormalizedNode normalizedNode) {
- String nodePath = parentPath + "/"+ normalizedNode.getIdentifier().toString();
+ String nodePath = parentPath + "/"+ PathUtils.toString(normalizedNode.getIdentifier());
if(nodePath.toString().equals(path)){
output = normalizedNode;
package org.opendaylight.controller.cluster.datastore.node.utils;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
public class PathUtils {
+
public static String getParentPath(String currentElementPath){
StringBuilder parentPath = new StringBuilder();
}
return parentPath.toString();
}
+
+ /**
+ * Given a YangInstanceIdentifier return a serialized version of the same
+ * as a String
+ *
+ * @param path
+ * @return
+ */
+ public static String toString(YangInstanceIdentifier path){
+ StringBuilder sb = new StringBuilder();
+ Iterator<YangInstanceIdentifier.PathArgument> iterator =
+ path.getPathArguments().iterator();
+
+ while(iterator.hasNext()){
+ sb.append(toString(iterator.next()));
+ if(iterator.hasNext()){
+ sb.append("/");
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Given a YangInstanceIdentifier.PathArgument return a serialized version
+ * of the same as a String
+ *
+ * @param pathArgument
+ * @return
+ */
+ public static String toString(YangInstanceIdentifier.PathArgument pathArgument){
+ if(pathArgument instanceof YangInstanceIdentifier.NodeIdentifier){
+ return toString((YangInstanceIdentifier.NodeIdentifier) pathArgument);
+ } else if(pathArgument instanceof YangInstanceIdentifier.AugmentationIdentifier){
+ return toString((YangInstanceIdentifier.AugmentationIdentifier) pathArgument);
+ } else if(pathArgument instanceof YangInstanceIdentifier.NodeWithValue){
+ return toString((YangInstanceIdentifier.NodeWithValue) pathArgument);
+ } else if(pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates){
+ return toString((YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument);
+ }
+
+ return pathArgument.toString();
+ }
+
+ /**
+ * Given a serialized string version of a YangInstanceIdentifier convert
+ * to a YangInstanceIdentifier
+ *
+ * @param path
+ * @return
+ */
+ public static YangInstanceIdentifier toYangInstanceIdentifier(String path){
+ String[] segments = path.split("/");
+
+ List<YangInstanceIdentifier.PathArgument> pathArguments = new ArrayList<>();
+ for (String segment : segments) {
+ if (!"".equals(segment)) {
+ pathArguments.add(NodeIdentifierFactory.getArgument(segment));
+ }
+ }
+ return YangInstanceIdentifier.create(pathArguments);
+ }
+
+ private static String toString(YangInstanceIdentifier.NodeIdentifier pathArgument){
+ return pathArgument.getNodeType().toString();
+ }
+
+ private static String toString(YangInstanceIdentifier.AugmentationIdentifier pathArgument){
+ Set<QName> childNames = pathArgument.getPossibleChildNames();
+ final StringBuilder sb = new StringBuilder("AugmentationIdentifier{");
+ sb.append("childNames=").append(childNames).append('}');
+ return sb.toString();
+
+ }
+
+ private static String toString(YangInstanceIdentifier.NodeWithValue pathArgument){
+ return pathArgument.getNodeType().toString() + "[" + pathArgument.getValue() + "]";
+ }
+
+ private static String toString(YangInstanceIdentifier.NodeIdentifierWithPredicates pathArgument){
+ return pathArgument.getNodeType().toString() + '[' + pathArgument.getKeyValues() + ']';
+ }
+
}
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeGetter;
import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeNavigator;
+import org.opendaylight.controller.cluster.datastore.node.utils.PathUtils;
import org.opendaylight.controller.cluster.datastore.util.TestModel;
import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Container;
import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import java.util.ArrayList;
import java.util.List;
import static junit.framework.Assert.assertEquals;
}
private YangInstanceIdentifier instanceIdentifierFromString(String s) {
-
- String[] ids = s.split("/");
-
- List<YangInstanceIdentifier.PathArgument> pathArguments = new ArrayList<>();
- for (String nodeId : ids) {
- if (!"".equals(nodeId)) {
- pathArguments.add(NodeIdentifierFactory.getArgument(nodeId));
- }
- }
- final YangInstanceIdentifier instanceIdentifier =
- YangInstanceIdentifier.create(pathArguments);
- return instanceIdentifier;
+ return PathUtils.toYangInstanceIdentifier(s);
}
-
@Test
public void testNormalizeNodeAttributesToProtoBuffNode() {
final NormalizedNode<?, ?> documentOne = TestModel.createTestContainer();
NormalizedNodeGetter normalizedNodeGetter = new NormalizedNodeGetter(id);
new NormalizedNodeNavigator(normalizedNodeGetter).navigate(
- YangInstanceIdentifier.builder().build().toString(), documentOne);
+ PathUtils.toString(YangInstanceIdentifier.builder().build()), documentOne);
// Validate the value of id can be retrieved from the normalized node
NormalizedNode output = normalizedNodeGetter.getOutput();
--- /dev/null
+package org.opendaylight.controller.cluster.datastore.node.utils;
+
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.util.TestModel;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class PathUtilsTest {
+
+ @Test
+ public void getParentPath(){
+ assertEquals("", PathUtils.getParentPath("foobar"));
+ assertEquals("", PathUtils.getParentPath("/a"));
+ assertEquals("/a", PathUtils.getParentPath("/a/b"));
+ assertEquals("/a/b", PathUtils.getParentPath("/a/b/c"));
+ assertEquals("/a/b", PathUtils.getParentPath("a/b/c"));
+ }
+
+ @Test
+ public void toStringNodeIdentifier(){
+ YangInstanceIdentifier.PathArgument pathArgument = nodeIdentifier();
+
+ String expected = "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test";
+
+ assertEquals(expected , PathUtils.toString(pathArgument));
+ }
+
+ @Test
+ public void toStringAugmentationIdentifier(){
+ String expected = "AugmentationIdentifier{childNames=[(urn:opendaylight:flow:table:statistics?revision=2013-12-15)flow-table-statistics]}";
+
+ YangInstanceIdentifier.PathArgument pathArgument = augmentationIdentifier();
+
+ assertEquals(expected, PathUtils.toString(pathArgument));
+ }
+
+ @Test
+ public void toStringNodeWithValue(){
+
+ YangInstanceIdentifier.PathArgument pathArgument = nodeWithValue();
+
+ String expected = "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test[100]";
+
+ assertEquals(expected, PathUtils.toString(pathArgument));
+ }
+
+
+ @Test
+ public void toStringNodeIdentifierWithPredicates(){
+
+ YangInstanceIdentifier.PathArgument pathArgument = nodeIdentifierWithPredicates();
+
+ String expected = "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test[{(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id=100}]";
+
+ assertEquals(expected, PathUtils.toString(pathArgument));
+ }
+
+ @Test
+ public void toStringYangInstanceIdentifier(){
+
+ YangInstanceIdentifier path =
+ YangInstanceIdentifier.create(nodeIdentifier())
+ .node(nodeIdentifierWithPredicates())
+ .node(augmentationIdentifier()).node(nodeWithValue());
+
+
+ String expected = "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test/" +
+ "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test[{(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id=100}]/" +
+ "AugmentationIdentifier{childNames=[(urn:opendaylight:flow:table:statistics?revision=2013-12-15)flow-table-statistics]}/" +
+ "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test[100]";
+
+ assertEquals(expected, PathUtils.toString(path));
+
+ }
+
+ @Test
+ public void toYangInstanceIdentifier(){
+ String expected = "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test/" +
+ "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test[{(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)id=100}]/" +
+ "AugmentationIdentifier{childNames=[(urn:opendaylight:flow:table:statistics?revision=2013-12-15)flow-table-statistics]}/" +
+ "(urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test?revision=2014-03-13)test[100]";
+
+ YangInstanceIdentifier yangInstanceIdentifier =
+ PathUtils.toYangInstanceIdentifier(expected);
+
+ String actual = PathUtils.toString(yangInstanceIdentifier);
+
+ assertEquals(expected, actual);
+
+ }
+
+ private YangInstanceIdentifier.NodeIdentifier nodeIdentifier(){
+ return new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME);
+ }
+
+ private YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier(){
+ Set<QName> childNames = new HashSet();
+ childNames.add(QNameFactory.create("(urn:opendaylight:flow:table:statistics?revision=2013-12-15)flow-table-statistics"));
+
+ return new YangInstanceIdentifier.AugmentationIdentifier(childNames);
+ }
+
+ private YangInstanceIdentifier.NodeWithValue nodeWithValue(){
+ return new YangInstanceIdentifier.NodeWithValue(TestModel.TEST_QNAME, Integer.valueOf(100));
+ }
+
+ private YangInstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifierWithPredicates(){
+ Map<QName, Object> keys = new HashMap<>();
+
+ keys.put(TestModel.ID_QNAME, Integer.valueOf(100));
+
+ return new YangInstanceIdentifier.NodeIdentifierWithPredicates(TestModel.TEST_QNAME, keys);
+ }
+}
this.identifier = TransactionIdentifier.builder().memberName(memberName).counter(
counter.getAndIncrement()).build();
- LOG.debug("Created txn {}", identifier);
+ LOG.debug("Created txn {} of type {}", identifier, transactionType);
}
package org.opendaylight.controller.cluster.datastore.messages;
import com.google.common.base.Preconditions;
-import org.opendaylight.controller.protobuff.messages.shard.ShardManagerMessages;
/**
* The FindPrimary message is used to locate the primary of any given shard
*
*/
public class FindPrimary implements SerializableMessage{
- public static final Class SERIALIZABLE_CLASS = ShardManagerMessages.FindPrimary.class;
+ public static final Class SERIALIZABLE_CLASS = FindPrimary.class;
private final String shardName;
public FindPrimary(String shardName){
@Override
public Object toSerializable() {
- return ShardManagerMessages.FindPrimary.newBuilder().setShardName(shardName).build();
+ return this;
}
public static FindPrimary fromSerializable(Object message){
- return new FindPrimary(((ShardManagerMessages.FindPrimary)message).getShardName());
+ return (FindPrimary) message;
}
}
package org.opendaylight.controller.cluster.datastore.messages;
-import org.opendaylight.controller.protobuff.messages.shard.ShardManagerMessages;
public class PrimaryFound implements SerializableMessage {
- public static final Class SERIALIZABLE_CLASS = ShardManagerMessages.PrimaryFound.class;
+ public static final Class SERIALIZABLE_CLASS = PrimaryFound.class;
private final String primaryPath;
public PrimaryFound(String primaryPath) {
@Override
public Object toSerializable() {
- return ShardManagerMessages.PrimaryFound.newBuilder().setPrimaryPath(primaryPath).build();
+ return this;
}
public static PrimaryFound fromSerializable(Object message){
- return new PrimaryFound(((ShardManagerMessages.PrimaryFound)message).getPrimaryPath());
+ return (PrimaryFound) message;
}
}
package org.opendaylight.controller.cluster.datastore.messages;
import com.google.common.base.Preconditions;
-import org.opendaylight.controller.protobuff.messages.shard.ShardManagerMessages;
public class PrimaryNotFound implements SerializableMessage {
- public static final Class SERIALIZABLE_CLASS = ShardManagerMessages.PrimaryNotFound.class;
+ public static final Class SERIALIZABLE_CLASS = PrimaryNotFound.class;
private final String shardName;
@Override
public Object toSerializable() {
- return ShardManagerMessages.PrimaryNotFound.newBuilder().setShardName(shardName).build();
+ return this;
}
public static PrimaryNotFound fromSerializable(Object message){
- return new PrimaryNotFound(((ShardManagerMessages.PrimaryNotFound)message).getShardName());
+ return (PrimaryNotFound) message;
}
}
}
@Override
- public synchronized DOMStoreThreePhaseCommitCohort ready(final SnapshotBackedWriteTransaction writeTx) {
+ public DOMStoreThreePhaseCommitCohort ready(final SnapshotBackedWriteTransaction writeTx) {
LOG.debug("Tx: {} is submitted. Modifications: {}", writeTx.getIdentifier(), writeTx.getMutatedView());
return new ThreePhaseCommitImpl(writeTx);
}
implements DOMStoreReadTransaction {
private static final Logger LOG = LoggerFactory.getLogger(SnapshotBackedReadTransaction.class);
- private DataTreeSnapshot stableSnapshot;
+ private volatile DataTreeSnapshot stableSnapshot;
public SnapshotBackedReadTransaction(final Object identifier, final DataTreeSnapshot snapshot) {
super(identifier);
LOG.debug("Tx: {} Read: {}", getIdentifier(), path);
checkNotNull(path, "Path must not be null.");
- if(stableSnapshot == null) {
+ final DataTreeSnapshot snapshot = stableSnapshot;
+ if (snapshot == null) {
return Futures.immediateFailedCheckedFuture(new ReadFailedException("Transaction is closed"));
}
try {
- return Futures.immediateCheckedFuture(stableSnapshot.readNode(path));
+ return Futures.immediateCheckedFuture(snapshot.readNode(path));
} catch (Exception e) {
LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e);
return Futures.immediateFailedCheckedFuture(new ReadFailedException("Read failed",e));
}
}
- @Override public CheckedFuture<Boolean, ReadFailedException> exists(YangInstanceIdentifier path) {
+ @Override
+ public CheckedFuture<Boolean, ReadFailedException> exists(YangInstanceIdentifier path) {
LOG.debug("Tx: {} Exists: {}", getIdentifier(), path);
checkNotNull(path, "Path must not be null.");
final CompositeNode schemasNode =
(CompositeNode) NetconfMessageTransformUtil.findNode(schemasNodeResult.getResult(), DATA_STATE_SCHEMAS_IDENTIFIER);
+ if(schemasNode == null) {
+ logger.warn("{}: Unable to detect available schemas, get to {} was empty", id, STATE_SCHEMAS_IDENTIFIER);
+ return EMPTY;
+ }
+
return create(id, schemasNode);
}
import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode;
import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
+import java.util.Collections;
+import java.util.List;
+
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+
class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener {
private final Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class);
@Override
public void onSuccess(Optional<Topology> topologyOptional) {
if (topologyOptional.isPresent()) {
- Topology topologyData = topologyOptional.get();
- for (Link link : topologyData.getLink()) {
+ List<Link> linkList = topologyOptional.get().getLink() != null
+ ? topologyOptional.get().getLink() : Collections.<Link> emptyList();
+ for (Link link : linkList) {
if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) {
transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link));
}
@Override
public void onSuccess(Optional<Topology> topologyOptional) {
if (topologyOptional.isPresent()) {
- Topology topologyData = topologyOptional.get();
- for (Link link : topologyData.getLink()) {
+ List<Link> linkList = topologyOptional.get().getLink() != null
+ ? topologyOptional.get().getLink() : Collections.<Link> emptyList();
+ for (Link link : linkList) {
if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) {
transaction.delete(LogicalDatastoreType.OPERATIONAL, linkPath(link));
}
if(configs != null && !configs.isEmpty()) {
configPusher.pushConfigs(configs);
}
- registration = context.registerService(ConfigPusher.class.getName(), configPusher, null);
- configPusher.process(autoCloseables, platformMBeanServer, persisterAggregator);
+ if(context != null) {
+ registration = context.registerService(ConfigPusher.class.getName(), configPusher, null);
+ configPusher.process(autoCloseables, platformMBeanServer, persisterAggregator);
+ } else {
+ logger.warn("Unable to process configs as BundleContext is null");
+ }
} catch (InterruptedException e) {
logger.info("ConfigPusher thread stopped",e);
}
import java.io.IOException;
import org.opendaylight.controller.netconf.nettyutil.AbstractChannelInitializer;
import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.SshHandler;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandler;
import org.opendaylight.protocol.framework.SessionListenerFactory;
final class SshClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
@Override
public void initialize(final Channel ch, final Promise<NetconfClientSession> promise) {
try {
- ch.pipeline().addFirst(SshHandler.createForNetconfSubsystem(authenticationHandler));
+ ch.pipeline().addFirst(AsyncSshHandler.createForNetconfSubsystem(authenticationHandler));
super.initialize(ch,promise);
} catch (final IOException e) {
throw new RuntimeException(e);
package org.opendaylight.controller.netconf.it;
import static java.util.Arrays.asList;
-import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import ch.ethz.ssh2.Connection;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProviderImpl;
}
public AuthenticationHandler getAuthHandler() throws IOException {
- final AuthenticationHandler authHandler = mock(AuthenticationHandler.class);
- doAnswer(new Answer() {
- @Override
- public Object answer(final InvocationOnMock invocation) throws Throwable {
- Connection conn = (Connection) invocation.getArguments()[0];
- conn.authenticateWithPassword("user", "pwd");
- return null;
- }
- }).when(authHandler).authenticate(any(Connection.class));
- doReturn("auth handler").when(authHandler).toString();
- return authHandler;
+ return new LoginPassword("user", "pwd");
}
}
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>ganymed</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </dependency>
<dependency>
<groupId>org.openexi</groupId>
<artifactId>nagasena</artifactId>
<groupId>xmlunit</groupId>
<artifactId>xmlunit</artifactId>
</dependency>
+
</dependencies>
<build>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>ch.ethz.ssh2, com.google.common.base, com.google.common.collect, io.netty.buffer,
+ <Import-Package>org.apache.sshd.*, ch.ethz.ssh2, com.google.common.base, com.google.common.collect, io.netty.buffer,
io.netty.channel, io.netty.channel.socket, io.netty.handler.codec, io.netty.handler.ssl, io.netty.util,
io.netty.util.concurrent, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax,
javax.xml.transform.stream, org.opendaylight.controller.netconf.api,
package org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication;
import ch.ethz.ssh2.Connection;
-
import java.io.IOException;
+import org.apache.sshd.ClientSession;
/**
* Class providing authentication facility to SSH handler.
*/
public abstract class AuthenticationHandler {
public abstract void authenticate(Connection connection) throws IOException;
+
+
+ public abstract String getUsername();
+
+ public abstract org.apache.sshd.client.future.AuthFuture authenticate(final ClientSession session) throws IOException;
}
package org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication;
-import ch.ethz.ssh2.Connection;
-
import java.io.IOException;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.client.future.AuthFuture;
+
+import ch.ethz.ssh2.Connection;
+
/**
* Class Providing username/password authentication option to
* {@link org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.SshHandler}
@Override
public void authenticate(Connection connection) throws IOException {
- boolean isAuthenticated = connection.authenticateWithPassword(username, password);
+ final boolean isAuthenticated = connection.authenticateWithPassword(username, password);
if (!isAuthenticated) {
throw new IOException("Authentication failed.");
}
}
+
+ @Override
+ public String getUsername() {
+ return username;
+ }
+
+ @Override
+ public AuthFuture authenticate(final ClientSession session) throws IOException {
+ session.addPasswordIdentity(password);
+ return session.auth();
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client;
+
+import com.google.common.base.Preconditions;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelOutboundHandlerAdapter;
+import io.netty.channel.ChannelPromise;
+import java.io.IOException;
+import java.net.SocketAddress;
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoInputStream;
+import org.apache.sshd.common.io.IoReadFuture;
+import org.apache.sshd.common.util.Buffer;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Netty SSH handler class. Acts as interface between Netty and SSH library.
+ */
+public class AsyncSshHandler extends ChannelOutboundHandlerAdapter {
+
+ private static final Logger logger = LoggerFactory.getLogger(AsyncSshHandler.class);
+ public static final String SUBSYSTEM = "netconf";
+
+ public static final SshClient DEFAULT_CLIENT = SshClient.setUpDefaultClient();
+
+ public static final int SSH_DEFAULT_NIO_WORKERS = 8;
+
+ static {
+ // TODO make configurable, or somehow reuse netty threadpool
+ DEFAULT_CLIENT.setNioWorkers(SSH_DEFAULT_NIO_WORKERS);
+ DEFAULT_CLIENT.start();
+ }
+
+ private final AuthenticationHandler authenticationHandler;
+ private final SshClient sshClient;
+
+ private SshReadAsyncListener sshReadAsyncListener;
+ private ClientChannel channel;
+ private ClientSession session;
+ private ChannelPromise connectPromise;
+
+ public static AsyncSshHandler createForNetconfSubsystem(final AuthenticationHandler authenticationHandler) throws IOException {
+ return new AsyncSshHandler(authenticationHandler, DEFAULT_CLIENT);
+ }
+
+ /**
+ *
+ * @param authenticationHandler
+ * @param sshClient started SshClient
+ * @throws IOException
+ */
+ public AsyncSshHandler(final AuthenticationHandler authenticationHandler, final SshClient sshClient) throws IOException {
+ this.authenticationHandler = Preconditions.checkNotNull(authenticationHandler);
+ this.sshClient = Preconditions.checkNotNull(sshClient);
+ // Start just in case
+ sshClient.start();
+ }
+
+ private void startSsh(final ChannelHandlerContext ctx, final SocketAddress address) {
+ logger.debug("Starting SSH to {} on channel: {}", address, ctx.channel());
+
+ final ConnectFuture sshConnectionFuture = sshClient.connect(authenticationHandler.getUsername(), address);
+ sshConnectionFuture.addListener(new SshFutureListener<ConnectFuture>() {
+ @Override
+ public void operationComplete(final ConnectFuture future) {
+ if (future.isConnected()) {
+ handleSshSessionCreated(future, ctx);
+ } else {
+ handleSshSetupFailure(ctx, future.getException());
+ }
+ }
+ });
+ }
+
+ private synchronized void handleSshSessionCreated(final ConnectFuture future, final ChannelHandlerContext ctx) {
+ try {
+ logger.trace("SSH session created on channel: {}", ctx.channel());
+
+ session = future.getSession();
+ final AuthFuture authenticateFuture = authenticationHandler.authenticate(session);
+ authenticateFuture.addListener(new SshFutureListener<AuthFuture>() {
+ @Override
+ public void operationComplete(final AuthFuture future) {
+ if (future.isSuccess()) {
+ handleSshAuthenticated(session, ctx);
+ } else {
+ handleSshSetupFailure(ctx, future.getException());
+ }
+ }
+ });
+ } catch (final IOException e) {
+ handleSshSetupFailure(ctx, e);
+ }
+ }
+
+ private synchronized void handleSshAuthenticated(final ClientSession session, final ChannelHandlerContext ctx) {
+ try {
+ logger.debug("SSH session authenticated on channel: {}, server version: {}", ctx.channel(), session.getServerVersion());
+
+ channel = session.createSubsystemChannel(SUBSYSTEM);
+ channel.setStreaming(ClientChannel.Streaming.Async);
+ channel.open().addListener(new SshFutureListener<OpenFuture>() {
+ @Override
+ public void operationComplete(final OpenFuture future) {
+ if(future.isOpened()) {
+ handleSshChanelOpened(ctx);
+ } else {
+ handleSshSetupFailure(ctx, future.getException());
+ }
+ }
+ });
+
+
+ } catch (final IOException e) {
+ handleSshSetupFailure(ctx, e);
+ }
+ }
+
+ private synchronized void handleSshChanelOpened(final ChannelHandlerContext ctx) {
+ logger.trace("SSH subsystem channel opened successfully on channel: {}", ctx.channel());
+
+ connectPromise.setSuccess();
+ connectPromise = null;
+ ctx.fireChannelActive();
+
+ final IoInputStream asyncOut = channel.getAsyncOut();
+ sshReadAsyncListener = new SshReadAsyncListener(ctx, asyncOut);
+ }
+
+ private synchronized void handleSshSetupFailure(final ChannelHandlerContext ctx, final Throwable e) {
+ logger.warn("Unable to setup SSH connection on channel: {}", ctx.channel(), e);
+ connectPromise.setFailure(e);
+ connectPromise = null;
+ throw new IllegalStateException("Unable to setup SSH connection on channel: " + ctx.channel(), e);
+ }
+
+ @Override
+ public synchronized void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) {
+ try {
+ if(channel.getAsyncIn().isClosed() || channel.getAsyncIn().isClosing()) {
+ handleSshSessionClosed(ctx);
+ } else {
+ channel.getAsyncIn().write(toBuffer(msg));
+ ((ByteBuf) msg).release();
+ }
+ } catch (final Exception e) {
+ logger.warn("Exception while writing to SSH remote on channel {}", ctx.channel(), e);
+ throw new IllegalStateException("Exception while writing to SSH remote on channel " + ctx.channel(),e);
+ }
+ }
+
+ private static void handleSshSessionClosed(final ChannelHandlerContext ctx) {
+ logger.debug("SSH session closed on channel: {}", ctx.channel());
+ ctx.fireChannelInactive();
+ }
+
+ private Buffer toBuffer(final Object msg) {
+ // TODO Buffer vs ByteBuf translate, Can we handle that better ?
+ Preconditions.checkState(msg instanceof ByteBuf);
+ final ByteBuf byteBuf = (ByteBuf) msg;
+ final byte[] temp = new byte[byteBuf.readableBytes()];
+ byteBuf.readBytes(temp, 0, byteBuf.readableBytes());
+ return new Buffer(temp);
+ }
+
+ @Override
+ public synchronized void connect(final ChannelHandlerContext ctx, final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) throws Exception {
+ this.connectPromise = promise;
+ startSsh(ctx, remoteAddress);
+ }
+
+ @Override
+ public void close(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
+ disconnect(ctx, promise);
+ }
+
+ @Override
+ public synchronized void disconnect(final ChannelHandlerContext ctx, final ChannelPromise promise) throws Exception {
+ if(sshReadAsyncListener != null) {
+ sshReadAsyncListener.close();
+ }
+
+ session.close(false).addListener(new SshFutureListener<CloseFuture>() {
+ @Override
+ public void operationComplete(final CloseFuture future) {
+ if(future.isClosed() == false) {
+ session.close(true);
+ }
+ session = null;
+ }
+ });
+
+ channel = null;
+ }
+
+ /**
+ * Listener over async input stream from SSH session.
+ * This listeners schedules reads in a loop until the session is closed or read fails.
+ */
+ private static class SshReadAsyncListener implements SshFutureListener<IoReadFuture>, AutoCloseable {
+ private static final int BUFFER_SIZE = 8192;
+
+ private final ChannelHandlerContext ctx;
+
+ private IoInputStream asyncOut;
+ private Buffer buf;
+ private IoReadFuture currentReadFuture;
+
+ public SshReadAsyncListener(final ChannelHandlerContext ctx, final IoInputStream asyncOut) {
+ this.ctx = ctx;
+ this.asyncOut = asyncOut;
+ buf = new Buffer(BUFFER_SIZE);
+ asyncOut.read(buf).addListener(this);
+ }
+
+ @Override
+ public synchronized void operationComplete(final IoReadFuture future) {
+ if(future.getException() != null) {
+
+ if(asyncOut.isClosed() || asyncOut.isClosing()) {
+ // We are closing
+ handleSshSessionClosed(ctx);
+ } else {
+ logger.warn("Exception while reading from SSH remote on channel {}", ctx.channel(), future.getException());
+ throw new IllegalStateException("Exception while reading from SSH remote on channel " + ctx.channel(), future.getException());
+ }
+ }
+
+ if (future.getRead() > 0) {
+ ctx.fireChannelRead(Unpooled.wrappedBuffer(buf.array(), 0, future.getRead()));
+
+ // Schedule next read
+ buf = new Buffer(BUFFER_SIZE);
+ currentReadFuture = asyncOut.read(buf);
+ currentReadFuture.addListener(this);
+ }
+ }
+
+ @Override
+ public synchronized void close() throws Exception {
+ // Remove self as listener on close to prevent reading from closed input
+ if(currentReadFuture != null) {
+ currentReadFuture.removeListener(this);
+ }
+
+ asyncOut = null;
+ }
+ }
+}
+++ /dev/null
-/*
- * 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.nettyutil.handler.ssh.client;
-
-import java.io.IOException;
-
-/**
- * Abstract class providing mechanism of invoking various SSH level services.
- * Class is not allowed to be extended, as it provides its own implementations via instance initiators.
- */
-abstract class Invoker {
- private boolean invoked = false;
-
- private Invoker() {
- }
-
- protected boolean isInvoked() {
- return invoked;
- }
-
- public void setInvoked() {
- this.invoked = true;
- }
-
- abstract void invoke(SshSession session) throws IOException;
-
- public static Invoker netconfSubsystem(){
- return subsystem("netconf");
- }
-
- public static Invoker subsystem(final String subsystem) {
- return new Invoker() {
- @Override
- synchronized void invoke(SshSession session) throws IOException {
- if (isInvoked()) {
- throw new IllegalStateException("Already invoked.");
- }
- try {
- session.startSubSystem(subsystem);
- } finally {
- setInvoked();
- }
- }
- };
- }
-}
+++ /dev/null
-/*
- * 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.nettyutil.handler.ssh.client;
-
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.controller.netconf.nettyutil.handler.ssh.virtualsocket.VirtualSocket;
-
-/**
- * Wrapper class around GANYMED SSH java library.
- */
-class SshClient {
- private final VirtualSocket socket;
- private final Map<Integer, SshSession> openSessions = new HashMap<>();
- private final AuthenticationHandler authenticationHandler;
- private Connection connection;
-
- public SshClient(VirtualSocket socket, AuthenticationHandler authenticationHandler) throws IOException {
- this.socket = socket;
- this.authenticationHandler = authenticationHandler;
- }
-
- public SshSession openSession() throws IOException {
- if (connection == null) {
- connect();
- }
-
- Session session = connection.openSession();
- SshSession sshSession = new SshSession(session);
- openSessions.put(openSessions.size(), sshSession);
-
- return sshSession;
- }
-
- private void connect() throws IOException {
- connection = new Connection(socket);
-
- connection.connect();
- authenticationHandler.authenticate(connection);
- }
-
-
- public void close() {
- for (SshSession session : openSessions.values()){
- session.close();
- }
-
- openSessions.clear();
-
- if (connection != null) {
- connection.close();
- }
- }
-
- @Override
- public String toString() {
- return "SshClient{" +
- "socket=" + socket +
- '}';
- }
-}
+++ /dev/null
-/*
- * 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.nettyutil.handler.ssh.client;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelPromise;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.LinkedList;
-import java.util.Queue;
-import java.util.concurrent.atomic.AtomicBoolean;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * Worker thread class. Handles all downstream and upstream events in SSH Netty
- * pipeline.
- */
-class SshClientAdapter implements Runnable {
- private static final Logger logger = LoggerFactory.getLogger(SshClientAdapter.class);
-
- private static final int BUFFER_SIZE = 1024;
-
- private final SshClient sshClient;
- private final Invoker invoker;
-
- private OutputStream stdIn;
-
- private final Queue<ByteBuf> postponed = new LinkedList<>();
-
- private ChannelHandlerContext ctx;
- private ChannelPromise disconnectPromise;
-
- private final AtomicBoolean stopRequested = new AtomicBoolean(false);
-
- private final Object lock = new Object();
-
- public SshClientAdapter(final SshClient sshClient, final Invoker invoker) {
- this.sshClient = sshClient;
- this.invoker = invoker;
- }
-
- // TODO ganymed spawns a Thread that receives the data from remote inside TransportManager
- // Get rid of this thread and reuse Ganymed internal thread (not sure if its possible without modifications in ganymed)
- public void run() {
- try {
- final SshSession session = sshClient.openSession();
- invoker.invoke(session);
- final InputStream stdOut = session.getStdout();
-
- synchronized (lock) {
- stdIn = session.getStdin();
- while (postponed.peek() != null) {
- writeImpl(postponed.poll());
- }
- }
-
- while (!stopRequested.get()) {
- final byte[] readBuff = new byte[BUFFER_SIZE];
- final int c = stdOut.read(readBuff);
- if (c == -1) {
- continue;
- }
-
- ctx.fireChannelRead(Unpooled.copiedBuffer(readBuff, 0, c));
- }
- } catch (final Exception e) {
- logger.error("Unexpected exception", e);
- } finally {
- sshClient.close();
-
- synchronized (lock) {
- if (disconnectPromise != null) {
- ctx.disconnect(disconnectPromise);
- }
- }
- }
- }
-
- // TODO: needs rework to match netconf framer API.
- public void write(final ByteBuf message) throws IOException {
- synchronized (lock) {
- if (stdIn == null) {
- postponed.add(message);
- return;
- }
- writeImpl(message);
- }
- }
-
- private void writeImpl(final ByteBuf message) throws IOException {
- message.getBytes(0, stdIn, message.readableBytes());
- message.release();
- stdIn.flush();
- }
-
- public void stop(final ChannelPromise promise) {
- synchronized (lock) {
- stopRequested.set(true);
- disconnectPromise = promise;
- }
- }
-
- public Thread start(final ChannelHandlerContext ctx, final ChannelFuture channelFuture) {
- checkArgument(channelFuture.isSuccess());
- checkNotNull(ctx.channel().remoteAddress());
- synchronized (this) {
- checkState(this.ctx == null);
- this.ctx = ctx;
- }
- final String threadName = toString();
- final Thread thread = new Thread(this, threadName);
- thread.start();
- return thread;
- }
-
- @Override
- public String toString() {
- return "SshClientAdapter{" +
- "sshClient=" + sshClient +
- '}';
- }
-}
+++ /dev/null
-/*
- * 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.nettyutil.handler.ssh.client;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelOutboundHandlerAdapter;
-import io.netty.channel.ChannelPromise;
-import java.io.IOException;
-import java.net.SocketAddress;
-import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.controller.netconf.nettyutil.handler.ssh.virtualsocket.VirtualSocket;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Netty SSH handler class. Acts as interface between Netty and SSH library. All standard Netty message handling
- * stops at instance of this class. All downstream events are handed of to wrapped {@link org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.SshClientAdapter};
- */
-public class SshHandler extends ChannelOutboundHandlerAdapter {
- private static final Logger logger = LoggerFactory.getLogger(SshHandler.class);
- private static final String SOCKET = "socket";
-
- private final VirtualSocket virtualSocket = new VirtualSocket();
- private final SshClientAdapter sshClientAdapter;
-
-
- public static SshHandler createForNetconfSubsystem(AuthenticationHandler authenticationHandler) throws IOException {
- return new SshHandler(authenticationHandler, Invoker.netconfSubsystem());
- }
-
-
- public SshHandler(AuthenticationHandler authenticationHandler, Invoker invoker) throws IOException {
- SshClient sshClient = new SshClient(virtualSocket, authenticationHandler);
- this.sshClientAdapter = new SshClientAdapter(sshClient, invoker);
- }
-
- @Override
- public void handlerAdded(ChannelHandlerContext ctx){
- if (ctx.channel().pipeline().get(SOCKET) == null) {
- ctx.channel().pipeline().addFirst(SOCKET, virtualSocket);
- }
- }
-
- @Override
- public void handlerRemoved(ChannelHandlerContext ctx) {
- if (ctx.channel().pipeline().get(SOCKET) != null) {
- ctx.channel().pipeline().remove(SOCKET);
- }
- }
-
- @Override
- public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws IOException {
- this.sshClientAdapter.write((ByteBuf) msg);
- }
-
- @Override
- public void connect(final ChannelHandlerContext ctx,
- SocketAddress remoteAddress,
- SocketAddress localAddress,
- ChannelPromise promise) {
- ctx.connect(remoteAddress, localAddress, promise);
-
- promise.addListener(new ChannelFutureListener() {
- public void operationComplete(ChannelFuture channelFuture) {
- if (channelFuture.isSuccess()) {
- sshClientAdapter.start(ctx, channelFuture);
- } else {
- logger.debug("Failed to connect to remote host");
- }
- }}
- );
- }
-
- @Override
- public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
- sshClientAdapter.stop(promise);
- }
-}
+++ /dev/null
-/*
- * 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.nettyutil.handler.ssh.client;
-
-import ch.ethz.ssh2.Session;
-import ch.ethz.ssh2.channel.Channel;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Wrapper class for proprietary SSH sessions implementations
- */
-class SshSession implements Closeable {
- private final Session session;
-
- public SshSession(final Session session) {
- this.session = session;
- }
-
- public void startSubSystem(final String name) throws IOException {
- session.startSubSystem(name);
- }
-
- public InputStream getStdout() {
- return session.getStdout();
- }
-
- // FIXME according to http://www.ganymed.ethz.ch/ssh2/FAQ.html#blocking you should read data from both stdout and stderr to prevent window filling up (since stdout and stderr share a window)
- // FIXME stdErr is not used anywhere
- public InputStream getStderr() {
- return session.getStderr();
- }
-
- public OutputStream getStdin() {
- return session.getStdin();
- }
-
- @Override
- public void close() {
- if (session.getState() == Channel.STATE_OPEN || session.getState() == Channel.STATE_OPENING) {
- session.close();
- }
- }
-}
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>ganymed</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
import org.junit.Test;
import org.opendaylight.controller.netconf.netty.EchoClientHandler.State;
import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
-import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.SshHandler;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandler;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProviderImpl;
ChannelInitializer<NioSocketChannel> channelInitializer = new ChannelInitializer<NioSocketChannel>() {
@Override
public void initChannel(NioSocketChannel ch) throws Exception {
- ch.pipeline().addFirst(SshHandler.createForNetconfSubsystem(new LoginPassword("a", "a")));
+ ch.pipeline().addFirst(AsyncSshHandler.createForNetconfSubsystem(new LoginPassword("a", "a")));
ch.pipeline().addLast(echoClientHandler);
}
};
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
protected static final Logger logger = LoggerFactory
.getLogger(Activator.class);
+ /**
+ * Priority to determine whether to override existing protocol service.
+ */
+ private static final int PLUGIN_PRIORITY = 10;
/**
* Function that is used to communicate to dependency manager the list of
// Set the protocolPluginType property which will be used
// by SAL
props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), Node.NodeIDType.OPENFLOW);
+ props.put(GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(),
+ Integer.valueOf(PLUGIN_PRIORITY));
c.setInterface(IPluginInDataPacketService.class.getName(), props);
// Hook the services coming in from SAL, as optional in
// case SAL is not yet there, could happen
// Set the protocolPluginType property which will be used
// by SAL
props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), Node.NodeIDType.OPENFLOW);
+ props.put(GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(),
+ Integer.valueOf(PLUGIN_PRIORITY));
c.setInterface(new String[] {
IReadFilterInternalListener.class.getName(),
IPluginInReadService.class.getName() }, props);
// Set the protocolPluginType property which will be used
// by SAL
props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), Node.NodeIDType.OPENFLOW);
+ props.put(GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(),
+ Integer.valueOf(PLUGIN_PRIORITY));
c.setInterface(
new String[] { IPluginInFlowProgrammerService.class.getName(), IMessageListener.class.getName(),
IContainerListener.class.getName(), IInventoryShimExternalListener.class.getName(),
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.controller.sal.action;
/**
SET_NW_SRC("setNwSrc", 0, 0),
SET_NW_DST("setNwDst", 0, 0),
SET_NW_TOS("setNwTos", 0, 0x3f),
- SET_TP_SRC("setTpSrc", 1, 0xffff),
- SET_TP_DST("setTpDst", 1, 0xffff),
+ SET_TP_SRC("setTpSrc", 0, 0xffff), // Set transport source port
+ SET_TP_DST("setTpDst", 0, 0xffff), // Set transport destination port
SET_NEXT_HOP("setNextHop", 0, 0);
private String id;
-
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
STATICVLAN("staticvlan"),
CLUSTERINGSERVICES("clusteringservices"),
STARTUPHOME("configuration/startup/"),
- PROTOCOLPLUGINTYPE("protocolPluginType");
+ PROTOCOLPLUGINTYPE("protocolPluginType"),
+ PROTOCOLPLUGINPRIORITY("protocolPluginPriority");
private GlobalConstants(String name) {
this.name = name;
public String toString() {
return name;
}
-}
\ No newline at end of file
+}
-
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.controller.sal.action;
import org.opendaylight.controller.sal.core.ConstructionException;
action = new SetTpDst(65535);
Assert.assertTrue(action.isValid());
+ action = new SetTpSrc(0);
+ Assert.assertTrue(action.isValid());
+
action = new SetTpDst(0);
- Assert.assertFalse(action.isValid());
+ Assert.assertTrue(action.isValid());
action = new SetTpSrc(-1);
Assert.assertFalse(action.isValid());
-
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
import org.opendaylight.controller.sal.packet.Packet;
import org.opendaylight.controller.sal.packet.PacketResult;
import org.opendaylight.controller.sal.packet.RawPacket;
-import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.NetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* adding a new service, removing a service, going through all of
* them maybe different.
*/
- private ConcurrentHashMap<String, IPluginInDataPacketService>
+ private ConcurrentHashMap<String, ProtocolService<IPluginInDataPacketService>>
pluginInDataService =
- new ConcurrentHashMap<String, IPluginInDataPacketService>();
+ new ConcurrentHashMap<String, ProtocolService<IPluginInDataPacketService>>();
private Map<String, AtomicInteger> statistics = new HashMap<String, AtomicInteger>();
/**
String t = p.getNode()
.getType();
// Now locate the TX dispatcher
- IPluginInDataPacketService s = pluginInDataService
- .get(t);
- if (s != null) {
+ ProtocolService<IPluginInDataPacketService> service =
+ pluginInDataService.get(t);
+ if (service != null) {
try {
- s.transmitDataPacket(pkt);
+ service.getService().transmitDataPacket(pkt);
increaseStat("TXPacketSuccess");
} catch (Exception e) {
increaseStat("TXPacketFailedForException");
}
void setPluginInDataService(Map props, IPluginInDataPacketService s) {
- if (this.pluginInDataService == null) {
- logger.error("pluginInDataService store null");
- return;
- }
- String type = null;
- logger.trace("Received setPluginInDataService request");
- for (Object e : props.entrySet()) {
- Map.Entry entry = (Map.Entry) e;
- logger.trace("Prop key:({}) value:({})",entry.getKey(), entry.getValue());
- }
-
- Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
- if (value instanceof String) {
- type = (String) value;
- }
- if (type == null) {
- logger.error("Received a PluginInDataService without any "
- + "protocolPluginType provided");
- } else {
- this.pluginInDataService.put(type, s);
- logger.debug("Stored the PluginInDataService for type: {}", type);
- }
+ ProtocolService.set(this.pluginInDataService, props, s, logger);
}
void unsetPluginInDataService(Map props, IPluginInDataPacketService s) {
- if (this.pluginInDataService == null) {
- logger.error("pluginInDataService store null");
- return;
- }
-
- String type = null;
- logger.trace("Received unsetPluginInDataService request");
- for (Object e : props.entrySet()) {
- Map.Entry entry = (Map.Entry) e;
- logger.trace("Prop key:({}) value:({})",entry.getKey(), entry.getValue());
- }
-
- Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
- if (value instanceof String) {
- type = (String) value;
- }
- if (type == null) {
- logger.error("Received a PluginInDataService without any "
- + "protocolPluginType provided");
- } else if (this.pluginInDataService.get(type).equals(s)) {
- this.pluginInDataService.remove(type);
- logger.debug("Removed the PluginInDataService for type: {}", type);
- }
+ ProtocolService.unset(this.pluginInDataService, props, s, logger);
}
void setListenDataPacket(Map props, IListenDataPacket s) {
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
import org.opendaylight.controller.sal.match.Match;
import org.opendaylight.controller.sal.match.MatchType;
import org.opendaylight.controller.sal.utils.EtherTypes;
-import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.IPProtocols;
import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
import org.opendaylight.controller.sal.utils.Status;
protected static final Logger logger = LoggerFactory
.getLogger(FlowProgrammerService.class);
- private ConcurrentHashMap<String, IPluginInFlowProgrammerService> pluginFlowProgrammer;
+ private ConcurrentHashMap<String, ProtocolService<IPluginInFlowProgrammerService>> pluginFlowProgrammer;
private Set<IFlowProgrammerListener> listener;
private AtomicLong seq;
public FlowProgrammerService() {
- pluginFlowProgrammer = new ConcurrentHashMap<String, IPluginInFlowProgrammerService>();
+ pluginFlowProgrammer = new ConcurrentHashMap<String, ProtocolService<IPluginInFlowProgrammerService>>();
listener = new HashSet<IFlowProgrammerListener>();
seq = new AtomicLong();
/*
// Set the reference to the plugin flow programmer
public void setService(Map<String, Object> props, IPluginInFlowProgrammerService s) {
- if (this.pluginFlowProgrammer == null) {
- logger.error("pluginFlowProgrammer store null");
- return;
- }
-
- if (logger.isTraceEnabled()) {
- logger.trace("Got a service set request {}", s);
- for (Map.Entry<String, Object> entry : props.entrySet()) {
- logger.trace("Prop key:({}) value:({})", entry.getKey(), entry.getValue());
- }
- }
-
- String type = null;
- Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
- if (value instanceof String) {
- type = (String) value;
- }
- if (type == null) {
- logger.error("Received a pluginFlowProgrammer without any "
- + "protocolPluginType provided");
- } else {
- this.pluginFlowProgrammer.put(type, s);
- logger.debug("Stored the pluginFlowProgrammer for type: {}", type);
- }
+ ProtocolService.set(this.pluginFlowProgrammer, props, s, logger);
}
public void unsetService(Map<String, Object> props, IPluginInFlowProgrammerService s) {
- if (this.pluginFlowProgrammer == null) {
- logger.error("pluginFlowProgrammer store null");
- return;
- }
-
- logger.debug("Received unsetpluginFlowProgrammer request");
- if (logger.isTraceEnabled()) {
- logger.trace("Got a service set request {}", s);
- for (Map.Entry<String, Object> entry : props.entrySet()) {
- logger.trace("Prop key:({}) value:({})", entry.getKey(), entry.getValue());
- }
- }
-
- String type = null;
- Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
- if (value instanceof String) {
- type = (String) value;
- }
- if (type == null) {
- logger.error("Received a pluginFlowProgrammer without any "
- + "protocolPluginType provided");
- } else if (this.pluginFlowProgrammer.get(type).equals(s)) {
- this.pluginFlowProgrammer.remove(type);
- logger.debug("Removed the pluginFlowProgrammer for type: {}", type);
- }
+ ProtocolService.unset(this.pluginFlowProgrammer, props, s, logger);
}
public void setListener(IFlowProgrammerListener s) {
@Override
public Status addFlow(Node node, Flow flow) {
if (pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType()).addFlow(
- node, flow);
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().addFlow(node, flow);
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status removeFlow(Node node, Flow flow) {
if (pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType())
- .removeFlow(node, flow);
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().removeFlow(node, flow);
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status removeAllFlows(Node node) {
if (pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType())
- .removeAllFlows(node);
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().removeAllFlows(node);
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) {
if (pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType())
- .modifyFlow(node, oldFlow, newFlow);
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().modifyFlow(node, oldFlow, newFlow);
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status addFlowAsync(Node node, Flow flow) {
if (pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType()).addFlowAsync(
- node, flow, getNextRid());
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().addFlowAsync(node, flow, getNextRid());
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status removeFlowAsync(Node node, Flow flow) {
if (pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType())
- .removeFlowAsync(node, flow, getNextRid());
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().removeFlowAsync(node, flow, getNextRid());
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow) {
if (pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType())
- .modifyFlowAsync(node, oldFlow, newFlow, getNextRid());
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().modifyFlowAsync(node, oldFlow, newFlow, getNextRid());
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status syncSendBarrierMessage(Node node) {
if (this.pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType())
- .syncSendBarrierMessage(node);
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().syncSendBarrierMessage(node);
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
@Override
public Status asyncSendBarrierMessage(Node node) {
if (this.pluginFlowProgrammer != null) {
- if (this.pluginFlowProgrammer.get(node.getType()) != null) {
- return this.pluginFlowProgrammer.get(node.getType())
- .asyncSendBarrierMessage(node);
+ ProtocolService<IPluginInFlowProgrammerService> service =
+ this.pluginFlowProgrammer.get(node.getType());
+ if (service != null) {
+ return service.getService().asyncSendBarrierMessage(node);
}
}
return new Status(StatusCode.NOSERVICE, "Plugin unuvailable");
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.implementation.internal;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+import org.slf4j.Logger;
+
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+
+/**
+ * An instance of this class keeps a protocol plugin service handler.
+ *
+ * @param <T> Type of protocol plugin service.
+ */
+public final class ProtocolService<T> {
+ /**
+ * Default priority value.
+ */
+ private static final int DEFAULT_PRIORITY = 0;
+
+ /**
+ * A protocol plugin service handler.
+ */
+ private final T service;
+
+ /**
+ * A priority value assigned to this protocol plugin.
+ */
+ private final int priority;
+
+ /**
+ * Set protocol plugin service.
+ *
+ * @param map A map that keeps protocol plugin services.
+ * @param props Service properties.
+ * @param s Protocol plugin service.
+ * @param logger A logger instance.
+ * @param <S> Type of protocol plugin service.
+ */
+ public static <S> void set(ConcurrentMap<String, ProtocolService<S>> map,
+ Map<?, ?> props, S s, Logger logger) {
+ if (map == null) {
+ logger.error("Protocol plugin service store is null.");
+ return;
+ }
+ if (s == null) {
+ logger.error("Protocol plugin service is null.");
+ return;
+ }
+ if (props == null) {
+ logger.error("Service property is null.");
+ return;
+ }
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("Received set service request: {}", s);
+ for (Map.Entry<?, ?> entry: props.entrySet()) {
+ logger.trace("Prop key:({}) value:({})", entry.getKey(),
+ entry.getValue());
+ }
+ }
+
+ Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
+ if (!(value instanceof String)) {
+ logger.error("Unexpected protocol type: {}", value);
+ return;
+ }
+
+ String type = (String)value;
+ ProtocolService<S> service = new ProtocolService<S>(props, s);
+ ProtocolService<S> old = map.putIfAbsent(type, service);
+ while (old != null) {
+ // Compare priority value.
+ if (old.getPriority() >= service.getPriority()) {
+ logger.trace("Protocol plugin service for {} is already set: " +
+ "current={}, requested={}", type, old, service);
+ return;
+ }
+
+ if (map.replace(type, old, service)) {
+ break;
+ }
+ old = map.putIfAbsent(type, service);
+ }
+
+ logger.debug("Stored protocol plugin service for {}: {}",
+ type, service);
+ }
+
+ /**
+ * Unset protocol plugin service.
+ *
+ * @param map A map that keeps protocol plugin services.
+ * @param props Service properties.
+ * @param s Protocol plugin service.
+ * @param logger A logger instance.
+ * @param <S> Type of protocol plugin service.
+ */
+ public static <S> void unset(ConcurrentMap<String, ProtocolService<S>> map,
+ Map<?, ?> props, S s, Logger logger) {
+ if (map == null) {
+ logger.error("Protocol plugin service store is null.");
+ return;
+ }
+ if (s == null) {
+ logger.error("Protocol plugin service is null.");
+ return;
+ }
+ if (props == null) {
+ logger.error("Service property is null.");
+ return;
+ }
+
+ if (logger.isTraceEnabled()) {
+ logger.trace("Received unset service request: {}", s);
+ for (Map.Entry<?, ?> entry: props.entrySet()) {
+ logger.trace("Prop key:({}) value:({})",
+ entry.getKey(), entry.getValue());
+ }
+ }
+
+ Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
+ if (!(value instanceof String)) {
+ logger.error("Unexpected protocol type {}: service={}", value, s);
+ return;
+ }
+
+ String type = (String)value;
+ ProtocolService<S> plugin = new ProtocolService<S>(props, s);
+ if (map.remove(type, plugin)) {
+ logger.debug("Removed protocol plugin service for {}: {}",
+ type, plugin);
+ } else {
+ logger.trace("Ignore unset service request for {}: {}",
+ type, plugin);
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param props Protocol plugin service properties.
+ * @param s A protocol plugin service handler.
+ */
+ public ProtocolService(Map<?, ?> props, T s) {
+ service = s;
+
+ String key = GlobalConstants.PROTOCOLPLUGINPRIORITY.toString();
+ Object value = props.get(key);
+ if (value instanceof Integer) {
+ priority = ((Integer)value).intValue();
+ } else {
+ priority = DEFAULT_PRIORITY;
+ }
+ }
+
+ /**
+ * Return a protocol plugin service handler.
+ *
+ * @return A protocol plugin service handler.
+ */
+ public T getService() {
+ return service;
+ }
+
+ /**
+ * Return a priority value assigned to this protocol plugin.
+ *
+ * @return A priority value.
+ */
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * Determine whether the given object is identical to this object.
+ *
+ * @param o An object to be compared.
+ * @return {@code true} if identical. Otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o == null || o.getClass() != getClass()) {
+ return false;
+ }
+
+ ProtocolService plugin = (ProtocolService)o;
+ return (service.equals(plugin.service) && priority == plugin.priority);
+ }
+
+ /**
+ * Return the hash code of this object.
+ *
+ * @return The hash code.
+ */
+ @Override
+ public int hashCode() {
+ return service.hashCode() + (priority * 31);
+ }
+
+ /**
+ * Return a string representation of this instance.
+ *
+ * @return A string representation of this instance.
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("[service=");
+ return builder.append(service).append(", priority=").append(priority).
+ append(']').toString();
+ }
+}
-
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
import org.opendaylight.controller.sal.reader.NodeDescription;
import org.opendaylight.controller.sal.reader.NodeTableStatistics;
import org.opendaylight.controller.sal.utils.EtherTypes;
-import org.opendaylight.controller.sal.utils.GlobalConstants;
import org.opendaylight.controller.sal.utils.IPProtocols;
import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
import org.opendaylight.controller.sal.utils.NodeCreator;
public class ReadService implements IReadService, CommandProvider, IPluginOutReadService {
protected static final Logger logger = LoggerFactory.getLogger(ReadService.class);
- private ConcurrentHashMap<String, IPluginInReadService> pluginReader =
- new ConcurrentHashMap<String, IPluginInReadService>();
+ private ConcurrentHashMap<String, ProtocolService<IPluginInReadService>> pluginReader =
+ new ConcurrentHashMap<String, ProtocolService<IPluginInReadService>>();
private Set<IReadServiceListener> readerListeners =
new CopyOnWriteArraySet<IReadServiceListener>();
// Set the reference to the plugin flow Reader service
public void setService(Map<?, ?> props, IPluginInReadService s) {
- if (this.pluginReader == null) {
- logger.error("pluginReader store null");
- return;
- }
-
- logger.trace("Got a service set request {}", s);
- String type = null;
- for (Object e : props.entrySet()) {
- Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
- logger.trace("Prop key:({}) value:({})", entry.getKey(),
- entry.getValue());
- }
-
- Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
- if (value instanceof String) {
- type = (String) value;
- }
- if (type == null) {
- logger.error("Received a pluginReader without any "
- + "protocolPluginType provided");
- } else {
- this.pluginReader.put(type, s);
- logger.debug("Stored the pluginReader for type: {}", type);
- }
+ ProtocolService.set(this.pluginReader, props, s, logger);
}
public void unsetService(Map<?, ?> props, IPluginInReadService s) {
- if (this.pluginReader == null) {
- logger.error("pluginReader store null");
- return;
- }
-
- String type = null;
- logger.debug("Received unsetpluginReader request");
- for (Object e : props.entrySet()) {
- Map.Entry<?, ?> entry = (Map.Entry<?, ?>) e;
- logger.trace("Prop key:({}) value:({})", entry.getKey(),
- entry.getValue());
- }
-
- Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString());
- if (value instanceof String) {
- type = (String) value;
- }
- if (type == null) {
- logger.error("Received a pluginReader without any "
- + "protocolPluginType provided");
- } else if (this.pluginReader.get(type).equals(s)) {
- this.pluginReader.remove(type);
- logger.debug("Removed the pluginReader for type: {}", type);
- }
+ ProtocolService.unset(this.pluginReader, props, s, logger);
}
+
public void setReaderListener(IReadServiceListener service) {
logger.trace("Got a listener set request {}", service);
this.readerListeners.add(service);
@Override
public FlowOnNode readFlow(Node node, Flow flow) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readFlow(node, flow, true);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readFlow(node, flow, true);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public FlowOnNode nonCachedReadFlow(Node node, Flow flow) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readFlow(node, flow, false);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readFlow(node, flow, false);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public List<FlowOnNode> readAllFlows(Node node) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readAllFlow(node, true);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readAllFlow(node, true);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public List<FlowOnNode> nonCachedReadAllFlows(Node node) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readAllFlow(node, false);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readAllFlow(node, false);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public NodeDescription readDescription(Node node) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readDescription(node, true);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readDescription(node, true);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public NodeDescription nonCachedReadDescription(Node node) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readDescription(node, false);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readDescription(node, false);
}
}
logger.warn("Plugin {} unavailable", node.getType());
public NodeConnectorStatistics readNodeConnector(NodeConnector connector) {
Node node = connector.getNode();
if (pluginReader != null && node != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readNodeConnector(connector, true);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readNodeConnector(connector, true);
}
}
logger.warn("Plugin {} unavailable", node.getType());
NodeConnector connector) {
Node node = connector.getNode();
if (pluginReader != null && node != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readNodeConnector(connector, false);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readNodeConnector(connector, false);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public List<NodeConnectorStatistics> readNodeConnectors(Node node) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readAllNodeConnector(node, true);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readAllNodeConnector(node, true);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public List<NodeTableStatistics> readNodeTable(Node node) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readAllNodeTable(node, true);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readAllNodeTable(node, true);
}
}
logger.warn("Plugin {} unavailable", node.getType());
public NodeTableStatistics nonCachedReadNodeTable(NodeTable table) {
Node node = table.getNode();
if (pluginReader != null && node != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readNodeTable(table, false);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readNodeTable(table, false);
}
}
logger.warn("Plugin {} unavailable", node.getType());
public NodeTableStatistics readNodeTable(NodeTable table) {
Node node = table.getNode();
if (pluginReader != null && node != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readNodeTable(table, true);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readNodeTable(table, true);
}
}
logger.warn("Plugin {} unavailable", node.getType());
@Override
public List<NodeConnectorStatistics> nonCachedReadNodeConnectors(Node node) {
if (pluginReader != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .readAllNodeConnector(node, false);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().readAllNodeConnector(node, false);
}
}
logger.warn("Plugin {} unavailable", node.getType());
public long getTransmitRate(NodeConnector connector) {
Node node = connector.getNode();
if (pluginReader != null && node != null) {
- if (this.pluginReader.get(node.getType()) != null) {
- return this.pluginReader.get(node.getType())
- .getTransmitRate(connector);
+ ProtocolService<IPluginInReadService> service =
+ this.pluginReader.get(node.getType());
+ if (service != null) {
+ return service.getService().getTransmitRate(connector);
}
}
logger.warn("Plugin {} unavailable", node.getType());
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.implementation;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.opendaylight.controller.sal.implementation.internal.ProtocolService;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+
+/**
+ * Unit test for {@link ProtocolService}.
+ */
+public class ProtocolServiceTest {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(ProtocolServiceTest.class);
+
+ @Test
+ public void testInstance() {
+ HashSet<ProtocolService<ITestService>> set = new HashSet<>();
+ TestService sv1 = new TestService();
+ HashMap<String, Object> prop1 = new HashMap<>();
+
+ ProtocolService<ITestService> ps1 =
+ new ProtocolService<ITestService>(prop1, sv1);
+ assertEquals(sv1, ps1.getService());
+ // Default priority is 0.
+ assertEquals(0, ps1.getPriority());
+ assertTrue(set.add(ps1));
+ assertFalse(set.add(ps1));
+
+ // Specify the same service and priority.
+ String priKey = GlobalConstants.PROTOCOLPLUGINPRIORITY.toString();
+ prop1.put(priKey, Integer.valueOf(0));
+ ProtocolService<ITestService> ps2 =
+ new ProtocolService<ITestService>(prop1, sv1);
+ assertEquals(sv1, ps2.getService());
+ assertEquals(0, ps2.getPriority());
+ assertEquals(ps1, ps2);
+ assertFalse(set.add(ps1));
+
+ // Specify different priority.
+ prop1.put(priKey, Integer.valueOf(Integer.MAX_VALUE));
+ ps2 = new ProtocolService<ITestService>(prop1, sv1);
+ assertEquals(sv1, ps2.getService());
+ assertEquals(Integer.MAX_VALUE, ps2.getPriority());
+ assertFalse(ps1.equals(ps2));
+ assertTrue(set.add(ps2));
+ assertFalse(set.add(ps2));
+
+ // Specify another service.
+ TestService sv2 = new TestService();
+ prop1.put(priKey, Integer.valueOf(0));
+ ps2 = new ProtocolService<ITestService>(prop1, sv2);
+ assertEquals(sv2, ps2.getService());
+ assertEquals(0, ps2.getPriority());
+ assertFalse(ps1.equals(ps2));
+ assertTrue(set.add(ps2));
+ assertFalse(set.add(ps2));
+ }
+
+ @Test
+ public void testSetUnsetError() {
+ ConcurrentMap<String, ProtocolService<ITestService>> services =
+ new ConcurrentHashMap<>();
+ TestService sv = new TestService();
+ Map<String, Object> props = new HashMap<>();
+
+ // null service.
+ ProtocolService.set(services, props, null, LOG);
+ assertTrue(services.isEmpty());
+
+ ProtocolService.unset(services, props, null, LOG);
+ assertTrue(services.isEmpty());
+
+ // null service property.
+ ProtocolService.set(services, null, sv, LOG);
+ assertTrue(services.isEmpty());
+
+ ProtocolService.unset(services, null, sv, LOG);
+ assertTrue(services.isEmpty());
+
+ // Type is not specified.
+ ProtocolService.set(services, props, sv, LOG);
+ assertTrue(services.isEmpty());
+
+ ProtocolService.unset(services, props, sv, LOG);
+ assertTrue(services.isEmpty());
+
+ // null service map.
+ final String typeKey = GlobalConstants.PROTOCOLPLUGINTYPE.toString();
+ assertEquals(null, props.put(typeKey, "OF"));
+ ProtocolService.set(null, props, sv, LOG);
+ assertTrue(services.isEmpty());
+
+ ProtocolService.unset(null, props, sv, LOG);
+ assertTrue(services.isEmpty());
+ }
+
+ @Test
+ public void testSetUnset() {
+ ConcurrentMap<String, ProtocolService<ITestService>> serviceMap =
+ new ConcurrentHashMap<>();
+ ConcurrentMap<String, ProtocolService<ITestService>> expected =
+ new ConcurrentHashMap<>();
+
+ final String typeKey = GlobalConstants.PROTOCOLPLUGINTYPE.toString();
+ final String priKey = GlobalConstants.PROTOCOLPLUGINPRIORITY.toString();
+ final String[] protocols = {"OF", "PE", "PK"};
+ final int basePri = 0;
+ final int loop = 5;
+
+ // Should override the service if higher priority is specified.
+ for (String proto: protocols) {
+ for (int pri = basePri - loop + 1; pri <= basePri; pri++) {
+ TestService sv = new TestService();
+ Map<String, Object> props = new HashMap<>();
+ assertEquals(null, props.put(typeKey, proto));
+ assertEquals(null, props.put(priKey, Integer.valueOf(pri)));
+ ProtocolService.set(serviceMap, props, sv, LOG);
+
+ ProtocolService<ITestService> service = serviceMap.get(proto);
+ assertNotNull(service);
+ assertEquals(sv, service.getService());
+ assertEquals(pri, service.getPriority());
+
+ ProtocolService<ITestService> service1 =
+ new ProtocolService<ITestService>(props, sv);
+ expected.put(proto, service1);
+ assertEquals(expected, serviceMap);
+
+ // Unset service request should be ignored if different
+ // parameters are specified.
+ TestService another = new TestService();
+ ProtocolService.unset(serviceMap, props, another, LOG);
+ assertEquals(expected, serviceMap);
+
+ props.put(priKey, Integer.valueOf(Integer.MAX_VALUE));
+ ProtocolService.unset(serviceMap, props, sv, LOG);
+ assertEquals(expected, serviceMap);
+ }
+ }
+
+ // Should reject the set service request if lower priority is specified.
+ for (String proto: protocols) {
+ for (int pri = basePri - loop; pri < basePri; pri++) {
+ TestService sv = new TestService();
+ Map<String, Object> props = new HashMap<>();
+ assertEquals(null, props.put(typeKey, proto));
+ assertEquals(null, props.put(priKey, Integer.valueOf(pri)));
+ ProtocolService.set(serviceMap, props, sv, LOG);
+ assertEquals(expected, serviceMap);
+ }
+ }
+
+ // Unset protocol services.
+ for (String proto: protocols) {
+ ProtocolService<ITestService> service = expected.remove(proto);
+ assertNotNull(service);
+
+ ITestService sv = service.getService();
+ Map<String, Object> props = new HashMap<>();
+ assertEquals(null, props.put(typeKey, proto));
+ assertEquals(null, props.put(priKey, Integer.valueOf(basePri)));
+ ProtocolService.unset(serviceMap, props, sv, LOG);
+ assertEquals(expected, serviceMap);
+
+ // Should be ignored if the specified service does not exist.
+ ProtocolService.unset(serviceMap, props, sv, LOG);
+ assertEquals(expected, serviceMap);
+ }
+
+ assertTrue(serviceMap.isEmpty());
+ }
+}
+
+interface ITestService {
+}
+
+class TestService implements ITestService {
+}
/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2013-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,
var h3 = "Set Transport Source Port";
var placeholder = "Transport Source Port";
var id = one.f.flows.id.modal.action.modifyTransportSourcePort;
- var help = "Range: 1 - 65535";
+ var help = "Range: 0 - 65535";
var action = 'SET_TP_SRC';
var name = "Source Port";
var body = function() {
var h3 = "Set Transport Destination Port";
var placeholder = "Transport Destination Port";
var id = one.f.flows.id.modal.action.modifyTransportDestinationPort;
- var help = "Range: 1 - 65535";
+ var help = "Range: 0 - 65535";
var action = 'SET_TP_DST';
var name = "Destination Port";
var body = function() {
<module>opendaylight/distribution/opendaylight-karaf</module>
<module>opendaylight/distribution/opendaylight-karaf-resources</module>
<module>features</module>
+
+ <!-- archetypes -->
+ <module>opendaylight/archetypes</module>
</modules>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>