Merge "Bug 1576: Handle remote failures for write Tx async"
authorMoiz Raja <moraja@cisco.com>
Tue, 26 Aug 2014 18:33:11 +0000 (18:33 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 26 Aug 2014 18:33:11 +0000 (18:33 +0000)
124 files changed:
features/adsal/pom.xml
features/adsal/src/main/resources/features.xml
features/base/pom.xml
features/base/src/main/resources/features.xml
features/config-netty/src/main/resources/features.xml
features/config-persister/src/main/resources/features.xml
features/config/src/main/resources/features.xml
features/flow/src/main/resources/features.xml
features/mdsal/pom.xml
features/mdsal/src/main/resources/features.xml
features/netconf/pom.xml
features/netconf/src/main/resources/features.xml
features/nsf/pom.xml
features/nsf/src/main/resources/features.xml
features/protocol-framework/src/main/resources/features.xml
opendaylight/archetypes/opendaylight-configfile-archetype/pom.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/pom.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/src/main/resources/80-configfile.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-configfile-archetype/src/test/resources/projects/basic/archetype.properties [new file with mode: 0644]
opendaylight/archetypes/opendaylight-configfile-archetype/src/test/resources/projects/basic/goal.txt [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-distro-archetype/pom.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/archetype-resources/pom.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/test/resources/projects/basic/archetype.properties [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/test/resources/projects/basic/goal.txt [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-features/pom.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/META-INF/maven/archetype-metadata.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/pom.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/src/main/resources/features.xml [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-features/src/test/resources/projects/basic/archetype.properties [new file with mode: 0644]
opendaylight/archetypes/opendaylight-karaf-features/src/test/resources/projects/basic/goal.txt [new file with mode: 0644]
opendaylight/archetypes/pom.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java
opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java
opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/configuration/tomcat-server.xml
opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/etc/custom.properties
opendaylight/distribution/opendaylight-karaf/pom.xml
opendaylight/distribution/opendaylight/pom.xml
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-akka-raft/pom.xml
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeader.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeaderReply.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractActorTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingTransactionChain.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodec.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NormalizedNodeGetter.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactory.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/InstanceIdentifierUtils.java
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtilsTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactoryTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-config/pom.xml
opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/akka.conf
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChain.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/FindPrimary.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/PrimaryFound.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/PrimaryNotFound.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxyTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreTransactionChain.java
opendaylight/md-sal/sal-dom-xsql-config/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-dom-xsql-config/src/main/resources/04-xsql.xml [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedReadTransaction.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfStateSchemas.java
opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/Get.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTracker.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializer.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/NetconfState.java
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/GetTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java
opendaylight/netconf/netconf-netty-util/pom.xml
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfHelloMessageToXMLEncoder.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfXMLToMessageDecoder.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/authentication/AuthenticationHandler.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/Invoker.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshClient.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshClientAdapter.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshHandler.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshSession.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/ChannelInputStream.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/ChannelOutputStream.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/VirtualSocket.java [deleted file]
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ChunkedFramingMechanismEncoderTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/EOMFramingMechanismEncoderTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/FramingMechanismHandlerFactoryTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfChunkAggregatorTest.java
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfHelloMessageToXMLEncoderTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfXMLToHelloMessageDecoderTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfXMLToMessageDecoderTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/authentication/LoginPasswordTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/pom.xml
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberAware.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/action/ActionType.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/GlobalConstants.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/action/ActionTest.java
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/DataPacketService.java
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ProtocolService.java [new file with mode: 0644]
opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java
opendaylight/sal/implementation/src/test/java/org/opendaylight/controller/sal/implementation/ProtocolServiceTest.java [new file with mode: 0644]
opendaylight/web/flows/src/main/resources/js/page.js
pom.xml

index 0ccb17a664ef203a88aa01e263811d998f09222f..0ce976e2ef3beed38a8019cfc63074d04989a674 100644 (file)
@@ -9,7 +9,7 @@
   </parent>
   <artifactId>features-adsal</artifactId>
   <version>${sal.version}</version>
-  <packaging>pom</packaging>
+  <packaging>jar</packaging>
   <name>Features :: AD-SAL Features</name>
   <description>AD-SAL Features POM</description>
   <properties>
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>base-features</artifactId>
-      <version>${project.parent.version}</version>
+      <artifactId>features-base</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
-      <scope>runtime</scope>
+    </dependency>
+    <!-- test to validate features.xml -->
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-test</artifactId>
+    </dependency>
+    <!-- dependency for opendaylight-karaf-empty for use by testing -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>opendaylight-karaf-empty</artifactId>
+      <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>
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <systemPropertyVariables>
+            <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>
+            <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>
+            <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
+          </systemPropertyVariables>
+          <dependenciesToScan>
+           <dependency>org.opendaylight.yangtools:features-test</dependency>
+          </dependenciesToScan>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
index f955315164ced774198c742c5c8f55171abe58b3..e12ca8e5e990acc860dc9e56e4eed57ed9c2a0e0 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <features name="adsal-${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">
+   <repository>mvn:org.opendaylight.controller/features-base/${commons.opendaylight.version}/xml/features</repository>
    <feature name="odl-adsal-all" description="OpenDaylight AD-SAL All Features" version="${sal.version}">
       <feature version="${sal.version}">odl-adsal-core</feature>
       <feature version="${sal.networkconfiguration.version}">odl-adsal-networkconfiguration</feature>
       <feature version="${configuration.version}">odl-adsal-configuration</feature>
    </feature>
    <feature name="odl-adsal-core" description="OpenDaylight :: AD-SAL :: Core" version="${sal.version}">
-      <feature>base-felix-dm</feature>
-      <feature>base-dummy-console</feature>
+      <feature>odl-base-felix-dm</feature>
+      <feature>odl-base-dummy-console</feature>
       <feature version="${project.version}">odl-adsal-thirdparty</feature>
-      <bundle start="true" start-level="35">mvn:org.apache.commons/commons-lang3/${commons.lang3.version}</bundle>
+      <bundle start="true">mvn:org.apache.commons/commons-lang3/${commons.lang3.version}</bundle>
   <!--    <bundle>mvn:org.osgi/org.osgi.compendium/${osgi.compendium.version}</bundle> -->
       <bundle>mvn:org.opendaylight.controller/sal/${sal.version}</bundle>
       <bundle>mvn:org.opendaylight.controller/sal.implementation/${sal.implementation.version}</bundle>
    </feature>
    <feature name="odl-adsal-networkconfiguration" description="OpenDaylight :: AD-SAL :: Network Configuration" version="${sal.networkconfiguration.version}">
+      <feature>odl-adsal-core</feature>
       <bundle>mvn:org.opendaylight.controller/sal.networkconfiguration/${sal.networkconfiguration.version}</bundle>
       <bundle>mvn:org.opendaylight.controller/sal.networkconfiguration.implementation/${sal.networkconfiguration.version}</bundle>
    </feature>
@@ -28,8 +30,8 @@
    </feature>
    <feature name="odl-adsal-clustering" description="OpenDaylight :: AD-SAL :: Clustering" version="${clustering.services.version}">
       <feature>transaction</feature>
-      <feature>base-felix-dm</feature>
-      <feature>base-eclipselink-persistence</feature>
+      <feature>odl-base-felix-dm</feature>
+      <feature>odl-base-eclipselink-persistence</feature>
       <feature version="${sal.version}">odl-adsal-core</feature>
       <bundle>mvn:org.opendaylight.controller/clustering.services/${clustering.services.version}</bundle>
       <bundle>mvn:org.opendaylight.controller/clustering.services-implementation/${clustering.services_implementation.version}</bundle>
index d925f51b948cfe444a77a5875546e6986ec5ca26..ed8e2a8c20d2765ade8cbe42856f8b94460eeb40 100644 (file)
     <version>1.4.2-SNAPSHOT</version>
     <relativePath>../../opendaylight/commons/opendaylight</relativePath>
   </parent>
-  <artifactId>base-features</artifactId>
-  <packaging>pom</packaging>
+  <artifactId>features-base</artifactId>
+  <packaging>jar</packaging>
   <name>${project.artifactId}</name>
   <description>Base Features POM</description>
   <properties>
     <features.file>features.xml</features.file>
   </properties>
+  <dependencies>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+    </dependency>
+    <dependency>
+      <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>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-client</artifactId>
+    </dependency>
+    <!-- Jersey for JAXRS -->
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-server</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-fileupload</groupId>
+      <artifactId>commons-fileupload</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-net</groupId>
+      <artifactId>commons-net</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>eclipselink</groupId>
+      <artifactId>javax.persistence</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>eclipselink</groupId>
+      <artifactId>javax.resource</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>javax.servlet</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>javax.servlet.jsp</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.apache.felix.gogo.command</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.apache.felix.gogo.runtime</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.apache.felix.gogo.shell</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.equinox.cm</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.equinox.console</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.equinox.ds</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.equinox.launcher</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.equinox.util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.osgi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>equinoxSDK381</groupId>
+      <artifactId>org.eclipse.osgi.services</artifactId>
+    </dependency>
+    <!-- Gemini Web -->
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.gemini.web.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.gemini.web.extender</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.gemini.web.tomcat</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.virgo.kernel.equinox.extensions</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.virgo.util.common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.virgo.util.io</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.virgo.util.math</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.virgo.util.osgi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.virgo.util.osgi.manifest</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>geminiweb</groupId>
+      <artifactId>org.eclipse.virgo.util.parser.manifest</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-common</artifactId>
+    </dependency>
+
+    <!--Netty-->
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-handler</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.activation</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.annotation</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.ejb</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.el</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.mail.glassfish</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.servlet.jsp.jstl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.servlet.jsp.jstl.impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>javax.xml.rpc</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.catalina</artifactId>
+      <version>7.0.53.v201406061610</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.catalina.ha</artifactId>
+      <version>7.0.53.v201406070630</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.catalina.tribes</artifactId>
+      <version>7.0.53.v201406070630</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.coyote</artifactId>
+      <version>7.0.53.v201406070630</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.el</artifactId>
+      <version>7.0.53.v201406060720</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.jasper</artifactId>
+      <version>7.0.53.v201406070630</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.juli.extras</artifactId>
+      <version>7.0.53.v201406060720</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.tomcat.api</artifactId>
+      <version>7.0.53.v201406060720</version>
+    </dependency>
+    <dependency>
+      <groupId>orbit</groupId>
+      <artifactId>org.apache.tomcat.util</artifactId>
+      <version>7.0.53.v201406070630</version>
+    </dependency>
+    <dependency>
+      <groupId>org.aopalliance</groupId>
+      <artifactId>com.springsource.org.aopalliance</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.dependencymanager.shell</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.fileinstall</artifactId>
+    </dependency>
+    <!-- felix webconsole -->
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.webconsole</artifactId>
+      <classifier>all</classifier>
+    </dependency>
+
+    <dependency>
+      <groupId>org.codehaus.jettison</groupId>
+      <artifactId>jettison</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.equinox.http</groupId>
+      <artifactId>servlet</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.antlr</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.moxy</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.javassist</groupId>
+      <artifactId>javassist</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.spec.javax.transaction</groupId>
+      <artifactId>jboss-transaction-api_1.1_spec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.jolokia</groupId>
+      <artifactId>jolokia-osgi</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.json</groupId>
+      <artifactId>json</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.ow2.asm</groupId>
+      <artifactId>asm-all</artifactId>
+    </dependency>
+    <!-- Visual VM hook -->
+    <dependency>
+      <groupId>org.ow2.chameleon.management</groupId>
+      <artifactId>chameleon-mbeans</artifactId>
+    </dependency>
+
+    <!-- Third party depedencies -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>log4j-over-slf4j</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.aop</artifactId>
+    </dependency>
+    <!-- Add Pax Exam -->
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.asm</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.beans</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.context</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.context.support</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.expression</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.transaction</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>org.springframework.web.servlet</artifactId>
+    </dependency>
+    <!-- Spring security -->
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-taglibs</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>virgomirror</groupId>
+      <artifactId>org.eclipse.jdt.core.compiler.batch</artifactId>
+    </dependency>
+
+    <!-- test to validate features.xml -->
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-test</artifactId>
+      <version>0.6.2-SNAPSHOT</version>
+    </dependency>
+    <!-- dependency for opendaylight-karaf-empty for use by testing -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>opendaylight-karaf-empty</artifactId>
+      <version>1.4.2-SNAPSHOT</version>
+      <type>zip</type>
+    </dependency>
+  </dependencies>
   <build>
     <resources>
       <resource>
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <systemPropertyVariables>
+            <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>
+            <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>
+            <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
+          </systemPropertyVariables>
+          <dependenciesToScan>
+           <dependency>org.opendaylight.yangtools:features-test</dependency>
+          </dependenciesToScan>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
index c335600e21d35b33e90a09e977b8a9b505dc509c..999cf704d2bedf212a283864e6d8e4d74f10fd68 100644 (file)
@@ -1,35 +1,35 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<features name="base-${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">
+<features name="odl-base-${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">
 
-   <feature name="base-all" description="OpenDaylight Controller" version="${project.version}">
+   <feature name="odl-base-all" description="OpenDaylight Controller" version="${project.version}">
       <feature>http</feature>
       <feature>transaction</feature>
-      <feature>base-felix-dm</feature>
-      <feature>base-aries-spi-fly</feature>
-      <feature>base-dummy-console</feature>
-      <feature>base-apache-commons</feature>
-      <feature>base-eclipselink-persistence</feature>
-      <feature>base-gemini-web</feature>
-      <feature>base-tomcat</feature>
-      <feature>base-netty</feature>
-      <feature>base-jersey</feature>
-      <feature>base-jackson</feature>
-      <feature>base-spring-security</feature>
+      <feature>odl-base-felix-dm</feature>
+      <feature>odl-base-aries-spi-fly</feature>
+      <feature>odl-base-dummy-console</feature>
+      <feature>odl-base-apache-commons</feature>
+      <feature>odl-base-eclipselink-persistence</feature>
+      <feature>odl-base-gemini-web</feature>
+      <feature>odl-base-tomcat</feature>
+      <feature>odl-base-netty</feature>
+      <feature>odl-base-jersey</feature>
+      <feature>odl-base-jackson</feature>
+      <feature>odl-base-spring-security</feature>
    </feature>
-   <feature name="base-dummy-console" description="Temporary Dummy Console" version="1.1.0-SNAPSHOT">
+   <feature name="odl-base-dummy-console" description="Temporary Dummy Console" version="1.1.0-SNAPSHOT">
       <bundle>mvn:org.opendaylight.controller/dummy-console/1.1.0-SNAPSHOT</bundle>
    </feature>
-   <feature name="base-felix-dm" description="Felix Dependency Manager" version="${felix.dependencymanager.version}">
-      <bundle start-level="35">mvn:org.osgi/org.osgi.compendium/${osgi.compendium.version}</bundle>
-      <bundle start-level="35">mvn:org.apache.felix/org.apache.felix.dependencymanager/${felix.dependencymanager.version}</bundle>
-      <bundle start-level="35">mvn:org.apache.felix/org.apache.felix.dependencymanager.shell/${felix.dependencymanager.shell.version}</bundle>
+   <feature name="odl-base-felix-dm" description="Felix Dependency Manager" version="${felix.dependencymanager.version}">
+      <bundle>mvn:org.osgi/org.osgi.compendium/${osgi.compendium.version}</bundle>
+      <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager/${felix.dependencymanager.version}</bundle>
+      <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager.shell/${felix.dependencymanager.shell.version}</bundle>
    </feature>
-   <feature name="base-aries-spi-fly" description="Aries SPI Fly" version="${spifly.version}">
-      <bundle start-level="35">mvn:org.apache.aries/org.apache.aries.util/1.1.0</bundle>
-      <bundle start-level="35">mvn:org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle/${spifly.version}</bundle>
-      <bundle start-level="35">mvn:org.ow2.asm/asm-all/4.0</bundle>
+   <feature name="odl-base-aries-spi-fly" description="Aries SPI Fly" version="${spifly.version}">
+      <bundle>mvn:org.apache.aries/org.apache.aries.util/1.1.0</bundle>
+      <bundle>mvn:org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle/${spifly.version}</bundle>
+      <bundle>mvn:org.ow2.asm/asm-all/4.0</bundle>
    </feature>
-   <feature name='base-netty' version='${netty.version}'>
+   <feature name='odl-base-netty' version='${netty.version}'>
       <bundle>wrap:mvn:io.netty/netty-buffer/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-codec/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-transport/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-codec-http/${netty.version}</bundle>
       <bundle>mvn:org.opendaylight.controller.thirdparty/ganymed/1.1-SNAPSHOT</bundle>
    </feature>
-   <feature name="base-jersey" description="Jersey" version="${jersey.version}">
-      <feature>base-gemini-web</feature>
-      <bundle>mvn:org.opendaylight.controller.thirdparty/com.sun.jersey.jersey-servlet/${jersey.version}</bundle>
+   <feature name="odl-base-jersey" description="Jersey" version="${jersey.version}">
+      <feature>odl-base-gemini-web</feature>
       <bundle>mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
       <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
       <bundle>mvn:com.sun.jersey/jersey-client/${jersey.version}</bundle>
       <bundle>mvn:com.sun.jersey/jersey-servlet/${jersey.version}</bundle>
    </feature>
-   <feature name="base-jersey2-osgi" description="OSGi friendly Jersey" version="${jersey2.publisher.version}">
+   <feature name="odl-base-jersey2-osgi" description="OSGi friendly Jersey" version="${jersey2.publisher.version}">
       <feature>http</feature>
       <bundle>mvn:com.eclipsesource.jaxrs/jersey-all/${jersey2.version}</bundle>
       <bundle>mvn:com.eclipsesource.jaxrs/publisher/${jersey2.publisher.version}</bundle>
-      <bundle start="true" start-level="35">mvn:javax.ws.rs/javax.ws.rs-api/${jsr311.v2.api.version}</bundle>
+      <bundle start="true">mvn:javax.ws.rs/javax.ws.rs-api/${jsr311.v2.api.version}</bundle>
       <bundle>mvn:javax.annotation/javax.annotation-api/${javax.annotation.version}</bundle>
     </feature>
-   <feature name="base-jackson" description="Jackson JAX-RS" version="${jackson.version}">
-      <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version}</bundle>
-      <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version}</bundle>
-      <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version}</bundle>
-      <bundle start="true" start-level="35">mvn:org.codehaus.jettison/jettison/${jettison.version}</bundle>
-      <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/${jackson.version}</bundle>
-      <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson.version}</bundle>
-      <bundle start="true" start-level="35">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson.version}</bundle>
+   <feature name="odl-base-jackson" description="Jackson JAX-RS" version="${jackson.version}">
+      <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
+      <bundle>mvn:com.sun.jersey/jersey-client/${jersey.version}</bundle>
+      <bundle start="true">mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version}</bundle>
+      <bundle start="true">mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version}</bundle>
+      <bundle start="true">mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version}</bundle>
+      <bundle start="true">mvn:org.codehaus.jettison/jettison/${jettison.version}</bundle>
+      <bundle start="true">mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/${jackson.version}</bundle>
+      <bundle start="true">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson.version}</bundle>
+      <bundle start="true">mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson.version}</bundle>
    </feature>
-   <feature name="base-slf4j" description="SLF4J Logging" version="${slf4j.version}">
-      <bundle start-level="35">mvn:org.slf4j/slf4j-jdk14/1.7.2</bundle>
-      <bundle start-level="35">mvn:org.slf4j/slf4j-nop/1.7.2</bundle>
-      <bundle start-level="35">mvn:org.slf4j/slf4j-simple/1.7.2</bundle>
-      <bundle start="true" start-level="35">mvn:org.slf4j/slf4j-api/1.7.2</bundle>
+   <feature name="odl-base-slf4j" description="SLF4J Logging" version="${slf4j.version}">
+      <bundle>mvn:org.slf4j/slf4j-jdk14/1.7.2</bundle>
+      <bundle>mvn:org.slf4j/slf4j-nop/1.7.2</bundle>
+      <bundle>mvn:org.slf4j/slf4j-simple/1.7.2</bundle>
+      <bundle start="true">mvn:org.slf4j/slf4j-api/1.7.2</bundle>
    </feature>
-   <feature name="base-apache-commons" description="Apache Commons Libraries" version="${project.version}">
-      <bundle start="true" start-level="35">mvn:com.google.guava/guava/${guava.version}</bundle>
-      <bundle start="true" start-level="35">mvn:org.javassist/javassist/${javassist.version}</bundle>
-      <bundle start="true" start-level="35">mvn:commons-io/commons-io/${commons.io.version}</bundle>
-      <bundle start="true" start-level="35">mvn:commons-codec/commons-codec/${commons.codec.version}</bundle>
-      <bundle start="true" start-level="35">mvn:org.apache.commons/commons-lang3/${commons.lang3.version}</bundle>
-      <bundle start="true" start-level="35">mvn:commons-net/commons-net/${commons.net.version}</bundle>
+   <feature name="odl-base-apache-commons" description="Apache Commons Libraries" version="${project.version}">
+      <bundle start="true">mvn:com.google.guava/guava/${guava.version}</bundle>
+      <bundle start="true">mvn:org.javassist/javassist/${javassist.version}</bundle>
+      <bundle start="true">mvn:commons-io/commons-io/${commons.io.version}</bundle>
+      <bundle start="true">mvn:commons-codec/commons-codec/${commons.codec.version}</bundle>
+      <bundle start="true">mvn:org.apache.commons/commons-lang3/${commons.lang3.version}</bundle>
+      <bundle start="true">mvn:commons-net/commons-net/${commons.net.version}</bundle>
    </feature>
-   <feature name="base-eclipselink-persistence" description="EclipseLink Persistence API" version="2.0.4.v201112161009">
-      <bundle start="true" start-level="35">mvn:eclipselink/javax.persistence/2.0.4.v201112161009</bundle>
-      <bundle start="true" start-level="35">mvn:eclipselink/javax.resource/1.5.0.v200906010428</bundle>
-      <bundle start="true" start-level="35">mvn:org.eclipse.persistence/org.eclipse.persistence.moxy/2.5.0</bundle>
-      <bundle start="true" start-level="35">mvn:org.eclipse.persistence/org.eclipse.persistence.core/2.5.0</bundle>
+   <feature name="odl-base-eclipselink-persistence" description="EclipseLink Persistence API" version="2.0.4.v201112161009">
+      <bundle start="true">mvn:eclipselink/javax.persistence/2.0.4.v201112161009</bundle>
+      <bundle start="true">mvn:eclipselink/javax.resource/1.5.0.v200906010428</bundle>
+      <bundle start="true">mvn:org.eclipse.persistence/org.eclipse.persistence.moxy/2.5.0</bundle>
+      <bundle start="true">mvn:org.eclipse.persistence/org.eclipse.persistence.core/2.5.0</bundle>
    </feature>
-   <feature name="base-gemini-web" description="Gemini Web" version="${geminiweb.version}">
+   <feature name="odl-base-gemini-web" description="Gemini Web" version="${geminiweb.version}">
       <feature>http</feature>
       <feature>transaction</feature>
-      <feature>base-slf4j</feature>
-      <feature>base-felix-dm</feature>
-      <feature>base-jackson</feature>
-      <feature>base-apache-commons</feature>
-      <bundle start="true" start-level="35">mvn:com.google.code.gson/gson/${gson.version}</bundle>
-      <bundle start="true" start-level="35">mvn:commons-fileupload/commons-fileupload/${commons.fileupload.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.gemini.web.core/${geminiweb.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.gemini.web.extender/${geminiweb.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.common/${virgo.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.io/${virgo.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.math/${virgo.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.osgi/${virgo.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.osgi.manifest/${virgo.version}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.virgo.util.parser.manifest/${virgo.version}</bundle>
-      <bundle start="true" start-level="35">mvn:org.apache.felix/org.apache.felix.fileinstall/3.1.6</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.activation/1.1.0.v201211130549</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.annotation/1.1.0.v201209060031</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.ejb/3.1.1.v201204261316</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.el/2.2.0.v201108011116</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.mail.glassfish/1.4.1.v201108011116</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.xml.rpc/1.1.0.v201005080400</bundle>
-      <bundle start="true" start-level="35">mvn:org.eclipse.jetty.orbit/javax.servlet.jsp/2.2.0.v201112011158</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.servlet.jsp.jstl/1.2.0.v201105211821</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/javax.servlet.jsp.jstl.impl/1.2.0.v201210211230</bundle>
+      <feature>odl-base-slf4j</feature>
+      <feature>odl-base-felix-dm</feature>
+      <feature>odl-base-jackson</feature>
+      <feature>odl-base-apache-commons</feature>
+      <bundle start="true">mvn:com.google.code.gson/gson/${gson.version}</bundle>
+      <bundle start="true">mvn:commons-fileupload/commons-fileupload/${commons.fileupload.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.gemini.web.core/${geminiweb.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.gemini.web.extender/${geminiweb.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.virgo.util.common/${virgo.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.virgo.util.io/${virgo.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.virgo.util.math/${virgo.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.virgo.util.osgi/${virgo.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.virgo.util.osgi.manifest/${virgo.version}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.virgo.util.parser.manifest/${virgo.version}</bundle>
+      <bundle start="true">mvn:org.apache.felix/org.apache.felix.fileinstall/3.1.6</bundle>
+      <bundle start="true">mvn:orbit/javax.activation/1.1.0.v201211130549</bundle>
+      <bundle start="true">mvn:orbit/javax.annotation/1.1.0.v201209060031</bundle>
+      <bundle start="true">mvn:orbit/javax.ejb/3.1.1.v201204261316</bundle>
+      <bundle start="true">mvn:orbit/javax.el/2.2.0.v201108011116</bundle>
+      <bundle start="true">mvn:orbit/javax.mail.glassfish/1.4.1.v201108011116</bundle>
+      <bundle start="true">mvn:orbit/javax.xml.rpc/1.1.0.v201005080400</bundle>
+      <bundle start="true">mvn:org.eclipse.jetty.orbit/javax.servlet.jsp/2.2.0.v201112011158</bundle>
+      <bundle start="true">mvn:orbit/javax.servlet.jsp.jstl/1.2.0.v201105211821</bundle>
+      <bundle start="true">mvn:orbit/javax.servlet.jsp.jstl.impl/1.2.0.v201210211230</bundle>
    </feature>
-   <feature name="base-tomcat" description="OpenDaylight Tomcat" version="7.0.53">
-      <feature>base-gemini-web</feature>
-      <feature>base-eclipselink-persistence</feature>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.catalina/${commons.karaf.catalina}</bundle>
-      <bundle start="true" start-level="35">mvn:geminiweb/org.eclipse.gemini.web.tomcat/${geminiweb.version}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.catalina.ha/${commons.karaf.catalina.ha}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.catalina.tribes/${commons.karaf.catalina.tribes}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.coyote/${commons.karaf.coyote}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.el/${commons.karaf.el}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.jasper/${commons.karaf.jasper}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.juli.extras/${commons.karaf.juli.version}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.tomcat.api/${commons.karaf.tomcat.api}</bundle>
-      <bundle start="true" start-level="35">mvn:orbit/org.apache.tomcat.util/${commons.karaf.tomcat.util}</bundle>
+   <feature name="odl-base-tomcat" description="OpenDaylight Tomcat" version="7.0.53">
+      <feature>odl-base-gemini-web</feature>
+      <feature>odl-base-eclipselink-persistence</feature>
+      <bundle start="true">mvn:orbit/org.apache.catalina/${commons.karaf.catalina}</bundle>
+      <bundle start="true">mvn:geminiweb/org.eclipse.gemini.web.tomcat/${geminiweb.version}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.catalina.ha/${commons.karaf.catalina.ha}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.catalina.tribes/${commons.karaf.catalina.tribes}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.coyote/${commons.karaf.coyote}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.el/${commons.karaf.el}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.jasper/${commons.karaf.jasper}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.juli.extras/${commons.karaf.juli.version}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.tomcat.api/${commons.karaf.tomcat.api}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.tomcat.util/${commons.karaf.tomcat.util}</bundle>
       <bundle start="true" >mvn:org.opendaylight.controller/karaf-tomcat-security/${karaf.security.version}</bundle>
-      <bundle start="true" start-level="35">wrap:mvn:virgomirror/org.eclipse.jdt.core.compiler.batch/${eclipse.jdt.core.compiler.batch.version}</bundle>
+      <bundle start="true">wrap:mvn:virgomirror/org.eclipse.jdt.core.compiler.batch/${eclipse.jdt.core.compiler.batch.version}</bundle>
    </feature>
-   <feature name="base-spring" description="Opendaylight Spring Support" version="${spring.version}">
+   <feature name="odl-base-spring" description="Opendaylight Spring Support" version="${spring.version}">
       <bundle>mvn:org.ow2.asm/asm-all/${asm.version}</bundle>
       <bundle>mvn:org.aopalliance/com.springsource.org.aopalliance/${aopalliance.version}</bundle>
       <bundle>mvn:org.springframework/org.springframework.aop/${spring.version}</bundle>
       <bundle>mvn:org.springframework/org.springframework.expression/${spring.version}</bundle>
       <bundle>mvn:org.springframework/org.springframework.transaction/${spring.version}</bundle>
    </feature>
-   <feature name="base-spring-web" description="OpenDaylight Spring Web" version="${spring.version}">
-      <feature>base-spring</feature>
-      <feature>base-gemini-web</feature>
+   <feature name="odl-base-spring-web" description="OpenDaylight Spring Web" version="${spring.version}">
+      <feature>odl-base-spring</feature>
+      <feature>odl-base-gemini-web</feature>
       <bundle>mvn:org.springframework/org.springframework.web/${spring.version}</bundle>
       <bundle>mvn:org.springframework/org.springframework.web.servlet/${spring.version}</bundle>
    </feature>
-   <feature name="base-spring-security" description="OpenDaylight Spring Security" version="${spring-security.version}">
-      <feature>base-spring-web</feature>
+   <feature name="odl-base-spring-security" description="OpenDaylight Spring Security" version="${spring-security.version}">
+      <feature>odl-base-spring-web</feature>
       <bundle>mvn:org.springframework.security/spring-security-config/${spring-security.version}</bundle>
       <bundle>mvn:org.springframework.security/spring-security-core/${spring-security.version}</bundle>
       <bundle>mvn:org.springframework.security/spring-security-taglibs/${spring-security.version}</bundle>
index 7f57d8cb84cbb3b5d103799646c8ea787f8e0d88..f8df1aa58c979d5f5b5b1cfb4cc7e8f928754852 100644 (file)
@@ -4,7 +4,7 @@
           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">
   <repository>mvn:org.opendaylight.controller/features-config-persister/${config.version}/xml/features</repository>
-  <feature name='odl-config-netty' version='${project.version}'>
+  <feature name='odl-config-netty' version='${project.version}' description="OpenDaylight :: Config-Netty">
     <feature version='${project.version}'>odl-config-netty-config-api</feature>
     <bundle>mvn:org.opendaylight.controller/netty-event-executor-config/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/netty-threadgroup-config/${project.version}</bundle>
index a3c005b3bd8937425420c1eff652e89262657225..20fb19f5ff6a1218975f9703f6ad5310be601cdf 100644 (file)
@@ -6,11 +6,11 @@
   <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-netconf/${netconf.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
-  <feature name='odl-config-all' version='${project.version}'>
+  <feature name='odl-config-persister-all' version='${project.version}' description="OpenDaylight :: Config Persister:: All">
     <feature version='${project.version}'>odl-config-persister</feature>
     <feature version='${project.version}'>odl-config-startup</feature>
   </feature>
-  <feature name='odl-config-persister' version='${project.version}'>
+  <feature name='odl-config-persister' version='${project.version}' description="OpenDaylight :: Config Persister ">
     <feature version='${netconf.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-config-api</feature>
     <feature version='${yangtools.version}'>odl-yangtools-binding-generator</feature>
@@ -27,7 +27,7 @@
     <bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.core/${eclipse.persistence.version}</bundle>
     <bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.moxy/${eclipse.persistence.version}</bundle>
   </feature>
-  <feature name='odl-config-startup' version='${project.version}'>
+  <feature name='odl-config-startup' version='${project.version}' description="OpenDaylight :: Config Persister:: Config Startup">
     <feature version='${project.version}'>odl-config-netconf-connector</feature>
     <feature version='${project.version}'>odl-config-persister</feature>
     <feature version='${project.version}'>odl-netconf-impl</feature>
index 5027588acb2e9fce758cffffff77388400c21c68..b4dd03f4910d6761e7415c7d657851e15de356f5 100644 (file)
@@ -5,7 +5,7 @@
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
   <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
 
-  <feature name='odl-config-all' version='${project.version}'>
+  <feature name='odl-config-all' version='${project.version}' description="OpenDaylight :: Config :: All">
       <feature version='${mdsal.version}'>odl-mdsal-common</feature>
       <feature version='${project.version}'>odl-config-api</feature>
       <feature version='${project.version}'>odl-config-netty-config-api</feature>
@@ -13,7 +13,7 @@
       <feature version='${project.version}'>odl-config-manager</feature>
   </feature>
 
-  <feature name='odl-mdsal-common' version='${mdsal.version}'>
+  <feature name='odl-mdsal-common' version='${mdsal.version}' description="OpenDaylight :: Config :: All">
       <feature version='${yangtools.version}'>odl-yangtools-data-binding</feature>
       <bundle>mvn:org.opendaylight.controller/sal-common/${mdsal.version}</bundle>
       <bundle>mvn:org.opendaylight.controller/sal-common-api/${mdsal.version}</bundle>
       <bundle>mvn:org.opendaylight.controller/sal-common-util/${mdsal.version}</bundle>
   </feature>
 
-  <feature name='odl-config-api' version='${project.version}'>
+  <feature name='odl-config-api' version='${project.version}' description="OpenDaylight :: Config :: API">
     <bundle>mvn:org.opendaylight.controller/config-api/${project.version}</bundle>
     <feature version='${yangtools.version}'>odl-yangtools-common</feature>
     <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
   </feature>
 
-  <feature name='odl-config-netty-config-api' version='${project.version}'>
+  <feature name='odl-config-netty-config-api' version='${project.version}' description="OpenDaylight :: Config :: Netty Config API">
     <feature version='${project.version}'>odl-config-api</feature>
     <bundle>mvn:org.opendaylight.controller/netty-config-api/${project.version}</bundle>
     <bundle>mvn:io.netty/netty-transport/${netty.version}</bundle>
@@ -35,7 +35,7 @@
     <bundle>mvn:io.netty/netty-buffer/${netty.version}</bundle>
   </feature>
 
-  <feature name='odl-config-core' version='${project.version}'>
+  <feature name='odl-config-core' version='${project.version}' description="OpenDaylight :: Config :: Core">
     <feature version='${yangtools.version}'>odl-yangtools-common</feature>
     <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
     <feature version='${yangtools.version}'>odl-yangtools-binding-generator</feature>
@@ -49,7 +49,7 @@
     <bundle>mvn:com.google.guava/guava/${guava.version}</bundle>
     <bundle>mvn:org.javassist/javassist/${javassist.version}</bundle>
   </feature>
-  <feature name='odl-config-manager' version='${project.version}'>
+  <feature name='odl-config-manager' version='${project.version}' description="OpenDaylight :: Config :: Manager">
     <feature version='${project.version}'>odl-config-core</feature>
     <bundle>mvn:org.opendaylight.controller/config-manager/${project.version}</bundle>
   </feature>
index 3f914be4aeabacfef427189543a1a9f91fe7325f..05404586309e24af131236d14b83c4c2d6bcb1b0 100644 (file)
@@ -4,7 +4,7 @@
    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">
     <repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
-    <feature name='odl-flow-model' version='${project.version}'>
+    <feature name='odl-flow-model' version='${project.version}' description="OpenDaylight :: Flow :: Model">
         <feature version='${yangtools.version}'>odl-yangtools-models</feature>
         <bundle>mvn:org.opendaylight.controller.model/model-flow-base/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller.model/model-flow-service/${project.version}</bundle>
@@ -12,7 +12,7 @@
         <bundle>mvn:org.opendaylight.controller.model/model-inventory/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller.model/model-topology/${project.version}</bundle>
     </feature>
-    <feature name='odl-flow-services' version='${project.version}'>
+    <feature name='odl-flow-services' version='${project.version}' description="OpenDaylight :: Flow :: Services">
         <feature version='${project.version}'>odl-mdsal-broker</feature>
         <feature version='${project.version}'>odl-flow-model</feature>
         <bundle>mvn:org.opendaylight.controller.md/topology-manager/${project.version}</bundle>
index ac6b82b26fb355036ba92f4b2f26bc49df21e0c9..3a9de7abcd13cc74c80833a6152bd84a43e87003 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-broker-impl</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-dom-xsql</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-binding-api</artifactId>
       <artifactId>jersey-server</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.opendaylight.controller.thirdparty</groupId>
-      <artifactId>com.sun.jersey.jersey-servlet</artifactId>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-servlet</artifactId>
     </dependency>
     <dependency>
       <groupId>io.netty</groupId>
index a3d7ed0f83df6455006a4c94dbb52283d1438461..9e29fc84f813ffb15e4c55440824c2708785b538 100644 (file)
@@ -7,13 +7,14 @@
     <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.controller/features-config-persister/${config.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.controller/features-config-netty/${config.version}/xml/features</repository>
-    <feature name='odl-mdsal-all' version='${project.version}'>
+    <feature name='odl-mdsal-all' version='${project.version}' description="OpenDaylight :: MDSAL :: All">
         <feature version='${project.version}'>odl-mdsal-broker</feature>
         <feature version='${project.version}'>odl-mdsal-netconf-connector</feature>
         <feature version='${project.version}'>odl-restconf</feature>
+        <feature version='${project.version}'>odl-mdsal-xsql</feature>
         <feature version='${project.version}'>odl-toaster</feature>
     </feature>
-    <feature name='odl-mdsal-broker' version='${project.version}'>
+    <feature name='odl-mdsal-broker' version='${project.version}' description="OpenDaylight :: MDSAL :: Broker">
         <feature version='${yangtools.version}'>odl-yangtools-common</feature>
         <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
         <feature version='${mdsal.version}'>odl-mdsal-common</feature>
@@ -30,7 +31,7 @@
         <bundle>mvn:org.opendaylight.controller/sal-inmemory-datastore/${project.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.mdsal.configfile}">mvn:org.opendaylight.controller/md-sal-config/${mdsal.version}/xml/config</configfile>
     </feature>
-    <feature name='odl-mdsal-netconf-connector' version='${project.version}'>
+    <feature name='odl-mdsal-netconf-connector' version='${project.version}' description="OpenDaylight :: MDSAL :: Netconf Connector">
         <feature version='${project.version}'>odl-mdsal-broker</feature>
         <feature version='${netconf.version}'>odl-netconf-client</feature>
         <feature version='${yangtools.version}'>odl-yangtools-models</feature>
         <bundle>mvn:org.opendaylight.controller/netconf-config-dispatcher/${config.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.netconf.connector.configfile}">mvn:org.opendaylight.controller/netconf-connector-config/${netconf.version}/xml/config</configfile>
     </feature>
-    <feature name='odl-restconf' version='${project.version}'>
+    <feature name='odl-restconf' version='${project.version}' description="OpenDaylight :: Restconf">
         <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
         <feature>war</feature>
         <bundle>mvn:org.opendaylight.controller/sal-rest-connector/${project.version}</bundle>
         <bundle>mvn:com.google.code.gson/gson/${gson.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.thirdparty/com.sun.jersey.jersey-servlet/${jersey.version}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-servlet/${jersey.version}</bundle>
         <bundle>mvn:io.netty/netty-buffer/${netty.version}</bundle>
         <bundle>mvn:io.netty/netty-codec/${netty.version}</bundle>
         <bundle>mvn:io.netty/netty-codec-http/${netty.version}</bundle>
@@ -56,7 +57,7 @@
         <bundle>mvn:org.opendaylight.controller/sal-remote/${project.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.restconf.configfile}">mvn:org.opendaylight.controller/sal-rest-connector-config/${mdsal.version}/xml/config</configfile>
     </feature>
-    <feature name='odl-toaster' version='${project.version}'>
+    <feature name='odl-toaster' version='${project.version}' description="OpenDaylight :: Toaster">
         <feature version='${yangtools.version}'>odl-yangtools-common</feature>
         <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
         <feature version='${project.version}'>odl-mdsal-broker</feature>
@@ -65,4 +66,9 @@
         <bundle>mvn:org.opendaylight.controller.samples/sample-toaster-provider/${project.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.toaster.configfile}">mvn:org.opendaylight.controller.samples/toaster-config/${project.version}/xml/config</configfile>
     </feature>
+    <feature name ='odl-mdsal-xsql' version='${project.version}'>
+        <feature version='${project.version}'>odl-mdsal-broker</feature>
+        <bundle>mvn:org.opendaylight.controller/sal-dom-xsql/${project.version}</bundle>
+        <configfile finalname="${config.configfile.directory}/${config.xsql.configfile}">mvn:org.opendaylight.controller/sal-dom-xsql-config/${project.version}/xml/config</configfile>
+    </feature>
 </features>
index 106e54a338203453fca414f06b89bce81232a3bc..51d6f6291b08adb86157c75523bc93067401b906 100644 (file)
       <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>
index 0033b0d83c7e4bf02aea300b62cf0ee69be350ba..1453a5fb969a9d1e3f6b9f6bec88cebb59182d3f 100644 (file)
@@ -5,7 +5,7 @@
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
   <repository>mvn:org.opendaylight.controller/features-protocol-framework/${protocol-framework.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
-  <feature name='odl-netconf-all' version='${project.version}'>
+  <feature name='odl-netconf-all' version='${project.version}' description="OpenDaylight :: Netconf :: All">
     <feature version='${project.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
@@ -16,7 +16,7 @@
     <feature version='${project.version}'>odl-netconf-monitoring</feature>
   </feature>
 
-  <feature name='odl-netconf-api' version='${project.version}'>
+  <feature name='odl-netconf-api' version='${project.version}' description="OpenDaylight :: Netconf :: API">
     <feature version='${protocol-framework.version}'>odl-protocol-framework</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-api/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring/${project.version}</bundle>
@@ -24,7 +24,7 @@
     <bundle>mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf-inet-types.version}</bundle>
     <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types/${ietf-yang-types.version}</bundle>
   </feature>
-  <feature name='odl-netconf-mapping-api' version='${project.version}'>
+  <feature name='odl-netconf-mapping-api' version='${project.version}' description="OpenDaylight :: Netconf :: Mapping API">
     <feature version='${project.version}'>odl-netconf-api</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-mapping-api/${project.version}</bundle>
   </feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-util/${project.version}</bundle>
   </feature>
-    <feature name='odl-netconf-impl' version='${project.version}'>
+    <feature name='odl-netconf-impl' version='${project.version}' description="OpenDaylight :: Netconf :: Impl">
     <feature version='${project.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
     <feature version='${project.version}'>odl-netconf-netty-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-impl/${project.version}</bundle>
   </feature>
-  <feature name='odl-config-netconf-connector' version='${project.version}'>
+  <feature name='odl-config-netconf-connector' version='${project.version}' description="OpenDaylight :: Netconf :: Connector">
     <feature version='${config.version}'>odl-config-manager</feature>
     <feature version='${project.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
     <bundle>mvn:org.opendaylight.controller/config-netconf-connector/${project.version}</bundle>
   </feature>
-  <feature name='odl-netconf-netty-util' version='${project.version}'>
+  <feature name='odl-netconf-netty-util' version='${project.version}' description="OpenDaylight :: Netconf :: Netty Util">
     <feature version='${project.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <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:io.netty/netty-buffer/${netty.version}</bundle>
     <bundle>mvn:io.netty/netty-transport/${netty.version}</bundle>
   </feature>
-  <feature name='odl-netconf-client' version="${project.version}">
+  <feature name='odl-netconf-client' version='${project.version}' description="OpenDaylight :: Netconf :: Client">
     <feature version='${project.version}'>odl-netconf-netty-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-client/${project.version}</bundle>
-    <configfile finalname="${config.configfile.directory}/${config.netconf.client.configfile}">mvn:org.opendaylight.controller/netconf-config/${netconf.version}/xml/config</configfile>
+    <configfile finalname='${config.configfile.directory}/${config.netconf.client.configfile}'>mvn:org.opendaylight.controller/netconf-config/${netconf.version}/xml/config</configfile>
   </feature>
-  <feature name='odl-netconf-monitoring' version='${project.version}'>
+  <feature name='odl-netconf-monitoring' version='${project.version}' description="OpenDaylight :: Netconf :: Monitoring">
     <feature version='${project.version}'>odl-netconf-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-monitoring/${project.version}</bundle>
   </feature>
 
-</features>
\ No newline at end of file
+</features>
index 224aef1dacb040b33f3ef88872d86384fb436b96..5be411caae22212330ad5ba1104f2a66067dbae1 100644 (file)
     <relativePath>../../opendaylight/commons/opendaylight</relativePath>
   </parent>
   <artifactId>features-nsf</artifactId>
-  <packaging>pom</packaging>
+  <version>${nsf.version}</version>
+  <packaging>jar</packaging>
   <name>OpenDaylight :: Features :: Network Service Functions</name>
   <description>Feature for Network Service Functions</description>
   <properties>
     <features.file>features.xml</features.file>
   </properties>
+  <dependencies>
+    <!-- test to validate features.xml -->
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-test</artifactId>
+    </dependency>
+    <!-- dependency for opendaylight-karaf-empty for use by testing -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>opendaylight-karaf-empty</artifactId>
+      <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>
       <resource>
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <systemPropertyVariables>
+            <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>
+            <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>
+            <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
+          </systemPropertyVariables>
+          <dependenciesToScan>
+           <dependency>org.opendaylight.yangtools:features-test</dependency>
+          </dependenciesToScan>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
index 130d72e01ae588780ccaa8d7840be0727874e2da..8dc51f1644c48dd31e9bf911681ea6819d7dc32b 100644 (file)
@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <features name="nsf-${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">
+    <repository>mvn:org.opendaylight.controller/features-base/${commons.opendaylight.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-adsal/${sal.version}/xml/features</repository>
     <feature name="odl-nsf-all" description="OpenDaylight :: NSF :: All Network Service Functions" version="${project.version}">
         <feature version="${sal.version}">odl-adsal-all</feature>
         <feature version="${project.version}">odl-nsf-managers</feature>
@@ -11,7 +13,7 @@
     </feature>
 
     <feature name="odl-nsf-managers" description="OpenDaylight :: AD-SAL :: Network Service Functions" version="${project.version}">
-        <feature version="${project.version}">base-all</feature>
+        <feature version="${commons.opendaylight.version}">odl-base-all</feature>
         <feature version="${sal.version}">odl-adsal-all</feature>
         <bundle>mvn:org.opendaylight.controller/usermanager/${usermanager.version}</bundle>
         <bundle>mvn:org.opendaylight.controller/usermanager.implementation/${usermanager.version}</bundle>
         <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}">
-        <feature version="${project.version}">base-all</feature>
+        <feature version="${commons.opendaylight.version}">odl-base-all</feature>
         <feature version="${project.version}">odl-nsf-managers</feature>
-        <bundle start-level="35">mvn:org.ow2.asm/asm-all/${asm.version}</bundle>
+        <bundle>mvn:org.ow2.asm/asm-all/${asm.version}</bundle>
         <!--
             TODO : Resolve these in a follow-up commit
             <bundle>mvn:org.opendaylight.controller/httpservice-bridge/${httpservice-bridge.northbound.version}</bundle>
@@ -61,6 +63,7 @@
         <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>
index 6daa3432c14285d8746bcd7385b08e520213f330..46510bca469805cd190222787693fe50d9492e33 100644 (file)
@@ -4,7 +4,7 @@
           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">
   <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
-  <feature name='odl-protocol-framework' version='${project.version}'>
+  <feature name='odl-protocol-framework' version='${project.version}' description="OpenDaylight :: Protocol Framework">
     <feature version='${config.version}'>odl-config-api</feature>
     <feature version='${config.version}'>odl-config-netty-config-api</feature>
     <bundle>mvn:org.opendaylight.controller/protocol-framework/${protocol-framework.version}</bundle>
diff --git a/opendaylight/archetypes/opendaylight-configfile-archetype/pom.xml b/opendaylight/archetypes/opendaylight-configfile-archetype/pom.xml
new file mode 100644 (file)
index 0000000..38c8616
--- /dev/null
@@ -0,0 +1,52 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644 (file)
index 0000000..d404f99
--- /dev/null
@@ -0,0 +1,16 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/pom.xml b/opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/pom.xml
new file mode 100644 (file)
index 0000000..e217b9a
--- /dev/null
@@ -0,0 +1,60 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/src/main/resources/80-configfile.xml b/opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/src/main/resources/80-configfile.xml
new file mode 100644 (file)
index 0000000..432b947
--- /dev/null
@@ -0,0 +1,78 @@
+<?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&amp;revision=2013-11-19</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&amp;revision=2013-11-12</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup?module=threadgroup&amp;revision=2013-11-07</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:timer?module=netty-timer&amp;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>
diff --git a/opendaylight/archetypes/opendaylight-configfile-archetype/src/test/resources/projects/basic/archetype.properties b/opendaylight/archetypes/opendaylight-configfile-archetype/src/test/resources/projects/basic/archetype.properties
new file mode 100644 (file)
index 0000000..7a940e7
--- /dev/null
@@ -0,0 +1,6 @@
+#Mon Aug 25 05:45:18 CDT 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
+repoName=foo
diff --git a/opendaylight/archetypes/opendaylight-configfile-archetype/src/test/resources/projects/basic/goal.txt b/opendaylight/archetypes/opendaylight-configfile-archetype/src/test/resources/projects/basic/goal.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/pom.xml b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/pom.xml
new file mode 100644 (file)
index 0000000..8883c64
--- /dev/null
@@ -0,0 +1,38 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644 (file)
index 0000000..4c4f510
--- /dev/null
@@ -0,0 +1,8 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/archetype-resources/pom.xml b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/main/resources/archetype-resources/pom.xml
new file mode 100644 (file)
index 0000000..965c619
--- /dev/null
@@ -0,0 +1,285 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/test/resources/projects/basic/archetype.properties b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/test/resources/projects/basic/archetype.properties
new file mode 100644 (file)
index 0000000..dd29db6
--- /dev/null
@@ -0,0 +1,6 @@
+#Thu Aug 21 14:44:29 CDT 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
+repoName=foo
diff --git a/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/test/resources/projects/basic/goal.txt b/opendaylight/archetypes/opendaylight-karaf-distro-archetype/src/test/resources/projects/basic/goal.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/opendaylight/archetypes/opendaylight-karaf-features/pom.xml b/opendaylight/archetypes/opendaylight-karaf-features/pom.xml
new file mode 100644 (file)
index 0000000..4973a69
--- /dev/null
@@ -0,0 +1,36 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/META-INF/maven/archetype-metadata.xml b/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644 (file)
index 0000000..158e448
--- /dev/null
@@ -0,0 +1,14 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/pom.xml b/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/pom.xml
new file mode 100644 (file)
index 0000000..e135e6b
--- /dev/null
@@ -0,0 +1,194 @@
+<?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>
diff --git a/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/src/main/resources/features.xml b/opendaylight/archetypes/opendaylight-karaf-features/src/main/resources/archetype-resources/src/main/resources/features.xml
new file mode 100644 (file)
index 0000000..4a59657
--- /dev/null
@@ -0,0 +1,86 @@
+#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>
diff --git a/opendaylight/archetypes/opendaylight-karaf-features/src/test/resources/projects/basic/archetype.properties b/opendaylight/archetypes/opendaylight-karaf-features/src/test/resources/projects/basic/archetype.properties
new file mode 100644 (file)
index 0000000..bab8cd2
--- /dev/null
@@ -0,0 +1,6 @@
+#Thu Aug 21 23:46:25 CDT 2014
+package=it.pkg
+version=0.1-SNAPSHOT
+groupId=archetype.it
+artifactId=basic
+repoName=foo
diff --git a/opendaylight/archetypes/opendaylight-karaf-features/src/test/resources/projects/basic/goal.txt b/opendaylight/archetypes/opendaylight-karaf-features/src/test/resources/projects/basic/goal.txt
new file mode 100644 (file)
index 0000000..e69de29
index 36af861e84826e109ed53e97fadee123b6056c18..cb597c10bd09fe4375053ced97449e25a3b68dc0 100644 (file)
@@ -6,9 +6,9 @@
   </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>
@@ -39,5 +39,8 @@
   </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>
index 5ead566d9d41046b42c0cd7a873ba1983f90bcf6..8fd173c094db829670ea200c194f8b71aa96249e 100644 (file)
@@ -78,6 +78,7 @@
     <config.configfile.directory>etc/opendaylight/karaf</config.configfile.directory>
     <config.netty.configfile>00-netty.xml</config.netty.configfile>
     <config.mdsal.configfile>01-mdsal.xml</config.mdsal.configfile>
+    <config.xsql.configfile>04-xsql.xml</config.xsql.configfile>
     <config.netconf.client.configfile>01-netconf.xml</config.netconf.client.configfile>
     <config.toaster.configfile>03-toaster-sample.xml</config.toaster.configfile>
     <config.restconf.configfile>10-rest-connector.xml</config.restconf.configfile>
     <usermanager.implementation.version>0.4.2-SNAPSHOT</usermanager.implementation.version>
     <usermanager.northbound.version>0.0.2-SNAPSHOT</usermanager.northbound.version>
     <usermanager.version>0.4.2-SNAPSHOT</usermanager.version>
+    <nsf.version>0.4.2-SNAPSHOT</nsf.version>
     <web.version>0.4.2-SNAPSHOT</web.version>
     <xtend.dstdir>src/main/xtend-gen</xtend.dstdir>
     <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>jersey-core</artifactId>
         <version>${jersey.version}</version>
       </dependency>
-
       <dependency>
         <groupId>com.sun.jersey</groupId>
         <artifactId>jersey-server</artifactId>
         <version>${jersey.version}</version>
       </dependency>
+      <dependency>
+        <groupId>com.sun.jersey</groupId>
+        <artifactId>jersey-servlet</artifactId>
+        <version>${jersey-servlet.version}</version>
+      </dependency>
 
       <dependency>
         <groupId>com.typesafe.akka</groupId>
         <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>sal-connector-api</artifactId>
         <version>${mdsal.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-dom-xsql</artifactId>
+        <version>${mdsal.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal-core-api</artifactId>
         <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>
         <type>xml</type>
         <scope>runtime</scope>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>features-base</artifactId>
+        <version>${commons.opendaylight.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+        <scope>runtime</scope>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>features-adsal</artifactId>
         <type>xml</type>
         <scope>runtime</scope>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>features-nsf</artifactId>
+        <version>${nsf.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+        <scope>runtime</scope>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>features-mdsal</artifactId>
index dd73675070c95ce2bf3365bf8589843322ddf53d..de7621110e21637b93d1b3531fbe579470b2e6f1 100644 (file)
@@ -44,13 +44,13 @@ import org.slf4j.LoggerFactory;
  *
  */
 
-public class ConfigurationService implements IConfigurationService, ICacheUpdateAware<ConfigurationEvent, String> {
+public class ConfigurationService implements IConfigurationService, ICacheUpdateAware<String, String> {
     private static final Logger logger = LoggerFactory
             .getLogger(ConfigurationService.class);
     public static final String SAVE_EVENT_CACHE = "config.event.save";
     private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
     private IClusterGlobalServices clusterServices;
-    private ConcurrentMap <ConfigurationEvent, String> configEvent;
+    private ConcurrentMap<String, String> configEvent;
     private Set<IConfigurationAware> configurationAwareList = Collections
             .synchronizedSet(new HashSet<IConfigurationAware>());
     private ObjectReader objReader;
@@ -105,7 +105,7 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
     @Override
     public Status saveConfigurations() {
         if (configEvent != null) {
-            configEvent.put(ConfigurationEvent.SAVE, "");
+            configEvent.put(ConfigurationEvent.SAVE.toString(), "");
         }
         return saveConfigurationsInternal();
     }
@@ -183,7 +183,7 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
     }
 
     @Override
-    public void entryCreated(ConfigurationEvent key, String cacheName,
+    public void entryCreated(String key, String cacheName,
             boolean originLocal) {
         if (originLocal) {
             return;
@@ -191,18 +191,18 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
     }
 
     @Override
-    public void entryUpdated(ConfigurationEvent key, String new_value,
+    public void entryUpdated(String key, String new_value,
             String cacheName, boolean originLocal) {
         if (originLocal) {
             return;
         }
-        if (key == ConfigurationEvent.SAVE) {
+        if (key.equals(ConfigurationEvent.SAVE.toString())) {
             saveConfigurationsInternal();
         }
     }
 
     @Override
-    public void entryDeleted(ConfigurationEvent key, String cacheName,
+    public void entryDeleted(String key, String cacheName,
             boolean originLocal) {
         if (originLocal) {
             return;
@@ -230,7 +230,7 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
             logger.error("uninitialized clusterServices, can't retrieve cache");
             return;
         }
-        configEvent = (ConcurrentMap<ConfigurationEvent, String>) this.clusterServices.getCache(SAVE_EVENT_CACHE);
+        configEvent = (ConcurrentMap<String, String>) this.clusterServices.getCache(SAVE_EVENT_CACHE);
         if (configEvent == null) {
             logger.error("Failed to retrieve configuration Cache");
         }
index a36d4cc6d78588df5828b175de0facd9fe666f33..dcab1f63fbc1104e4225b0351455fb3de0db1d70 100644 (file)
@@ -47,11 +47,12 @@ import org.slf4j.LoggerFactory;
  */
 
 public class ContainerConfigurationService implements IConfigurationContainerService,
-        IConfigurationAware, ICacheUpdateAware<ConfigurationEvent, String> {
+        IConfigurationAware,
+        ICacheUpdateAware<String, String> {
     public static final String CONTAINER_SAVE_EVENT_CACHE = "config.container.event.save";
     private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class);
     private IClusterContainerServices clusterServices;
-    private ConcurrentMap <ConfigurationEvent, String> containerConfigEvent;
+    private ConcurrentMap<String, String> containerConfigEvent;
     // Directory which contains the startup files for this container
     private String root;
     private Set<IConfigurationContainerAware> configurationAwareList = Collections
@@ -142,12 +143,12 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
 
     @Override
     public Status saveConfigurations() {
-        containerConfigEvent.put(ConfigurationEvent.SAVE, "");
+        containerConfigEvent.put(ConfigurationEvent.SAVE.toString(), "");
         return saveConfiguration();
     }
 
     @Override
-    public void entryCreated(ConfigurationEvent key, String cacheName,
+    public void entryCreated(String key, String cacheName,
             boolean originLocal) {
         if (originLocal) {
             return;
@@ -155,19 +156,19 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
     }
 
     @Override
-    public void entryUpdated(ConfigurationEvent key, String new_value,
+    public void entryUpdated(String key, String new_value,
             String cacheName, boolean originLocal) {
         if (originLocal) {
             return;
         }
         logger.debug("Processing {} event", key);
-        if (key == ConfigurationEvent.SAVE) {
+        if (key.equals(ConfigurationEvent.SAVE.toString())) {
             saveConfiguration();
         }
     }
 
     @Override
-    public void entryDeleted(ConfigurationEvent key, String cacheName,
+    public void entryDeleted(String key, String cacheName,
             boolean originLocal) {
         if (originLocal) {
             return;
@@ -195,7 +196,8 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
             logger.error("uninitialized clusterServices, can't retrieve cache");
             return;
         }
-        containerConfigEvent = (ConcurrentMap<ConfigurationEvent, String>) this.clusterServices.getCache(CONTAINER_SAVE_EVENT_CACHE);
+        containerConfigEvent =
+                (ConcurrentMap<String, String>) this.clusterServices.getCache(CONTAINER_SAVE_EVENT_CACHE);
         if (containerConfigEvent == null) {
             logger.error("Failed to retrieve configuration Cache");
         }
index 73a46f0f8a21624365241abf7a42ec0f5403adfb..fbcd0a4c779ed4203a4f153f67604016f43085e6 100644 (file)
@@ -48,7 +48,7 @@
       <Host name="localhost" appBase=""
             unpackWARs="false" autoDeploy="false"
             deployOnStartup="false" createDirs="false">
-            <Realm className="org.opendaylight.controller.karafsecurity.ControllerCustomRealm />
+            <Realm className="org.opendaylight.controller.karafsecurity.ControllerCustomRealm" />
             <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
             <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                         prefix="web_access_log_" suffix=".txt" resolveHosts="false"
index e9a6992521250d612c1924e4f0fa46548f63d741..c2ac77a5d6f57b3ba24a581a700dead2fcc8a377 100644 (file)
@@ -1,6 +1,20 @@
 # 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:
@@ -105,3 +119,4 @@ java.util.logging.config.file=configuration/tomcat-logging.properties
 
 #Hosttracker hostsdb key scheme setting
 hosttracker.keyscheme=IP
+
index 5cbe412b2b0af28da537a95af2ace0766df8e120..cdc592428f9d685ab0e715a6e9f762e5a743cc83 100644 (file)
           down with testing... ie, no broken feature repos
     -->
 
+    <!-- AD-SAL Related Features -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-base</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-adsal</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-nsf</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
     <!-- MD-SAL Related Features -->
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
                         <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>
index d70bf4641192c488d043e2ba7ff4bc41279b1375..9a7677099dd8be04b4357b707c135a8279153a64 100644 (file)
           <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>
index 605cb9004a65235dd6cf66b0ff065514f54ad183..64c3d9c467bdeeae7726f4f462ab54a75f5e7775 100644 (file)
@@ -122,10 +122,15 @@ module flow-node-inventory {
             uses meter:meter;
         }
     }
-    
-    
-    grouping flow-node {
 
+    grouping ip-address-grouping {
+        leaf ip-address {
+            description "IP address of a flow capable node.";
+            type inet:ip-address;
+        }
+    }
+
+    grouping flow-node {
         leaf manufacturer {
             type string;
         }
@@ -145,6 +150,7 @@ module flow-node-inventory {
         uses tables;
         uses group:groups;
         uses meters;
+        uses ip-address-grouping;
         // TODO: ports
         
         container supported-match-types {
@@ -197,7 +203,16 @@ module flow-node-inventory {
             
         }
     }
-    
+
+    rpc get-node-ip-address {
+        input {
+            uses "inv:node-context-ref";
+        }
+        output {
+            uses ip-address-grouping;
+        }
+    }
+
     grouping flow-node-connector {
 
         uses port:flow-capable-port;
index 6c6760d789a086157bdb35a0a66d620db8057d3c..c184c44d7d0fae3661632e3a3bb77f1d86ff879e 100644 (file)
@@ -83,6 +83,7 @@
 
     <!-- Clustering -->
     <module>sal-remoterpc-connector</module>
+    <module>sal-dom-xsql-config</module>
   </modules>
 
   <build>
                     </goals>
                   </pluginExecutionFilter>
                   <action>
-                    <ignore></ignore>
+                    <ignore/>
                   </action>
                 </pluginExecution>
                 <pluginExecution>
                     </goals>
                   </pluginExecutionFilter>
                   <action>
-                    <ignore></ignore>
+                    <ignore/>
                   </action>
                 </pluginExecution>
               </pluginExecutions>
       </modules>
     </profile>
   </profiles>
-</project>
+</project>
\ No newline at end of file
index 3dcc546426165ac578486c5dd528b7b8cb4d0766..084ef16f575ce67c8725031e2742a86f1f7105d5 100644 (file)
       <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>
index ae8b6fe8e3aadc23a33cf57531a43ff9cefed8d4..988789b4011e4f3ba9e9e9abe6b0c3009704c810 100644 (file)
@@ -168,8 +168,7 @@ public abstract class RaftActor extends UntypedPersistentActor {
 
         } else if (message instanceof FindLeader) {
             getSender().tell(
-                new FindLeaderReply(
-                    context.getPeerAddress(currentBehavior.getLeaderId())),
+                new FindLeaderReply(getLeaderAddress()),
                 getSelf()
             );
 
@@ -183,12 +182,6 @@ public abstract class RaftActor extends UntypedPersistentActor {
 
             // 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.
@@ -269,18 +262,9 @@ public abstract class RaftActor extends UntypedPersistentActor {
      * @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);
     }
 
     /**
@@ -424,6 +408,21 @@ public abstract class RaftActor extends UntypedPersistentActor {
         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 {
 
index a60aea46e82965d0ded03eb7464941bf1a62f4af..98dd0d46531cadef35f8832a89237a1a95ae44fd 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.controller.cluster.raft.client.messages;
 
-public class FindLeader {
+import java.io.Serializable;
+
+public class FindLeader implements Serializable{
 
 }
index b36ef112b364371d01d9e7f411fdf27761938606..64c73508960144ab3f0095ba3af34c897217c336 100644 (file)
@@ -8,7 +8,9 @@
 
 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) {
index 1971432fb9844f747d39e37c8546c7568632f7c0..ec5381546964d7c8846ed446e4947baebe48380f 100644 (file)
@@ -10,20 +10,26 @@ package org.opendaylight.controller.cluster.raft;
 
 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;
     }
@@ -32,4 +38,12 @@ public abstract class AbstractActorTest {
         return system;
     }
 
+    protected static void deleteJournal() throws IOException {
+        File journal = new File("journal");
+
+        if(journal.exists()) {
+            FileUtils.deleteDirectory(journal);
+        }
+    }
+
 }
diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java
new file mode 100644 (file)
index 0000000..ff0ffeb
--- /dev/null
@@ -0,0 +1,137 @@
+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());
+    }
+
+
+}
index dbe7508cc8c185a33a35fcf072498041b589854c..2b753004c48265620628fdbc58a1e41a96a65c51 100644 (file)
@@ -1,6 +1,6 @@
 akka {
-
     loglevel = "DEBUG"
+    loggers = ["akka.testkit.TestEventListener", "akka.event.slf4j.Slf4jLogger"]
 
     actor {
         # enable to test serialization only.
@@ -12,6 +12,7 @@ akka {
         }
 
         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
index 24ec89ebb27da82f92fa569216ee7db5fc07d6cc..c71aa049c0622397773d5547faa773aac45ad7fd 100644 (file)
@@ -1,18 +1,41 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.controller.md.sal.binding.api;
 
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
+/**
+ * A chain of transactions.
+ * <p>
+ * For more information about transaction chaining and transaction chains
+ * see {@link TransactionChain}.
+ *
+ * @see TransactionChain
+ *
+ */
 public interface BindingTransactionChain extends TransactionFactory, TransactionChain<InstanceIdentifier<?>, DataObject> {
-
+    /**
+     * {@inheritDoc}
+     */
     @Override
     ReadOnlyTransaction newReadOnlyTransaction();
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     ReadWriteTransaction newReadWriteTransaction();
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     WriteTransaction newWriteOnlyTransaction();
-
 }
index 619a08eac5f30a6f3a7ff7f5f154b1be4c74bdbc..cc8deb81b31777ee6dd4aa3b5bf19a97f3ababb5 100644 (file)
@@ -20,22 +20,39 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * subscribe for changes to data under a given branch of the tree.
  * <p>
  * For more information on usage, please see the documentation in {@link AsyncDataBroker}.
+ *
+ * @see AsyncDataBroker
+ * @see TransactionChainFactory
  */
 public interface DataBroker extends TransactionFactory, AsyncDataBroker<InstanceIdentifier<?>, DataObject, DataChangeListener>, BindingService, TransactionChainFactory<InstanceIdentifier<?>, DataObject> {
-
+    /**
+     * {@inheritDoc}
+     */
     @Override
     ReadOnlyTransaction newReadOnlyTransaction();
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     ReadWriteTransaction newReadWriteTransaction();
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     WriteTransaction newWriteOnlyTransaction();
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     ListenerRegistration<DataChangeListener> registerDataChangeListener(LogicalDatastoreType store,
             InstanceIdentifier<?> path, DataChangeListener listener, DataChangeScope triggeringScope);
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     BindingTransactionChain createTransactionChain(TransactionChainListener listener);
 }
index f843b23f9b2cc9d15a55c2d9a4373cde3baffecc..53f96e44f4105b8ecd3f2125be2360bd54a0b0c4 100644 (file)
@@ -9,15 +9,14 @@ package org.opendaylight.controller.md.sal.binding.impl;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
-import java.util.ArrayList;
+
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
@@ -88,7 +87,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
             final Map<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized) {
         Map<InstanceIdentifier<?>, DataObject> newMap = new HashMap<>();
 
-        for (Map.Entry<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : sortedEntries(normalized)) {
+        for (Map.Entry<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : normalized.entrySet()) {
             try {
                 Optional<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> potential = getCodec().toBinding(entry);
                 if (potential.isPresent()) {
@@ -102,38 +101,6 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         return newMap;
     }
 
-    private static final Comparator<Entry<YangInstanceIdentifier, ?>> MAP_ENTRY_COMPARATOR = new Comparator<Entry<YangInstanceIdentifier, ?>>() {
-        @Override
-        public int compare(final Entry<YangInstanceIdentifier, ?> left, final Entry<YangInstanceIdentifier, ?> right) {
-            final Iterator<?> li = left.getKey().getPathArguments().iterator();
-            final Iterator<?> ri = right.getKey().getPathArguments().iterator();
-
-            // Iterate until left is exhausted...
-            while (li.hasNext()) {
-                if (!ri.hasNext()) {
-                    // Left is deeper
-                    return 1;
-                }
-
-                li.next();
-                ri.next();
-            }
-
-            // Check if right is exhausted
-            return ri.hasNext() ? -1 : 0;
-        }
-    };
-
-    private static <T> Iterable<Entry<YangInstanceIdentifier, T>> sortedEntries(final Map<YangInstanceIdentifier, T> map) {
-        if (!map.isEmpty()) {
-            ArrayList<Entry<YangInstanceIdentifier, T>> entries = new ArrayList<>(map.entrySet());
-            Collections.sort(entries, MAP_ENTRY_COMPARATOR);
-            return entries;
-        } else {
-            return Collections.emptySet();
-        }
-    }
-
     protected Set<InstanceIdentifier<?>> toBinding(final InstanceIdentifier<?> path,
             final Set<YangInstanceIdentifier> normalized) {
         Set<InstanceIdentifier<?>> hashSet = new HashSet<>();
index 344694381a222850fb23ccac0cc8415b3296f472..dba2908e9c4a9309bf3a1acba4e4fcc5974f7a03 100644 (file)
@@ -73,6 +73,7 @@ public class TestHelper {
                 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(), //
index 17bdb36e569612ef513a787e010aeb8583167984..d1ae264c3b912839a4332fc74766076859b754db 100644 (file)
@@ -32,7 +32,7 @@ public class NormalizedNodeToNodeCodec {
         String parentPath = "";
 
         if(id != null){
-            parentPath = PathUtils.getParentPath(id.toString());
+            parentPath = PathUtils.getParentPath(PathUtils.toString(id));
         }
 
 
index 31e6521a2861e65f1412b99818d4d47684e04c7b..32f3be82fcd0648e35796c5e3c835332825a20e9 100644 (file)
@@ -25,7 +25,7 @@ public class NormalizedNodeGetter implements
 
     @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;
index 1dd0f3b8278407752b91afbb24548eb857385cbc..25b65f01681ac4b9dcaa6354ec001c85bc531981 100644 (file)
 
 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();
 
@@ -27,4 +36,86 @@ public class PathUtils {
         }
         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() + ']';
+    }
+
 }
index 002b9ff82e53eea0b62fd98d97756926a2e21bea..5a8f5228619e9f80a091da123aa734fb59dcd85f 100644 (file)
 
 package org.opendaylight.controller.cluster.datastore.node.utils;
 
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import org.opendaylight.yangtools.yang.common.QName;
 
-import java.util.HashMap;
-import java.util.Map;
-
 public class QNameFactory {
-    private static final Map<String, QName> cache = new HashMap<>();
 
-    public static QName create(String name){
-        QName value = cache.get(name);
-        if(value == null){
-            synchronized (cache){
-                value = cache.get(name);
-                if(value == null) {
-                    value = QName.create(name);
-                    cache.put(name, value);
+    private static final int MAX_QNAME_CACHE_SIZE = 10000;
+
+    private static LoadingCache<String, QName> cache = CacheBuilder.newBuilder()
+        .maximumSize(MAX_QNAME_CACHE_SIZE)
+        .softValues()
+        .build(
+            new CacheLoader<String, QName>() {
+                public QName load(String key) {
+                    return QName.create(key);
                 }
             }
-        }
-        return value;
+        );
+
+
+    public static QName create(String name){
+        return cache.getUnchecked(name);
     }
 }
index 55cb341086078b79406d574c11cec8961813e6b6..0bb0d4fe8798b8623dc433d659f6ea550096c41e 100644 (file)
@@ -11,6 +11,7 @@
 package org.opendaylight.controller.cluster.datastore.util;
 
 import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
+import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory;
 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -222,7 +223,7 @@ public class InstanceIdentifierUtils {
 
             YangInstanceIdentifier.NodeWithValue nodeWithValue =
                 new YangInstanceIdentifier.NodeWithValue(
-                    QName.create(pathArgument.getNodeType().getValue()),
+                    QNameFactory.create(pathArgument.getNodeType().getValue()),
                     parseAttribute(pathArgument.getAttributes(0)));
 
             return nodeWithValue;
@@ -232,7 +233,7 @@ public class InstanceIdentifierUtils {
             YangInstanceIdentifier.NodeIdentifierWithPredicates
                 nodeIdentifierWithPredicates =
                 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
-                    QName.create(pathArgument.getNodeType().getValue()), toAttributesMap(pathArgument.getAttributesList()));
+                    QNameFactory.create(pathArgument.getNodeType().getValue()), toAttributesMap(pathArgument.getAttributesList()));
 
             return nodeIdentifierWithPredicates;
 
@@ -241,7 +242,7 @@ public class InstanceIdentifierUtils {
             Set<QName> qNameSet = new HashSet<>();
 
             for(NormalizedNodeMessages.Attribute attribute : pathArgument.getAttributesList()){
-                qNameSet.add(QName.create(attribute.getValue()));
+                qNameSet.add(QNameFactory.create(attribute.getValue()));
             }
 
             return new YangInstanceIdentifier.AugmentationIdentifier(qNameSet);
@@ -259,7 +260,7 @@ public class InstanceIdentifierUtils {
             String name = attribute.getName();
             Object value = parseAttribute(attribute);
 
-            map.put(QName.create(name), value);
+            map.put(QNameFactory.create(name), value);
         }
 
         return map;
index bdad86ddc1e8fb5521607fbb91a575a99e677d38..c42865c659192e0584ebe93a147fee655ab284c4 100644 (file)
@@ -13,9 +13,9 @@ package org.opendaylight.controller.cluster.datastore.node;
 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;
@@ -24,7 +24,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 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;
@@ -43,21 +42,9 @@ public class NormalizedNodeToNodeCodecTest {
   }
 
   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();
@@ -69,7 +56,7 @@ public class NormalizedNodeToNodeCodecTest {
 
     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();
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtilsTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtilsTest.java
new file mode 100644 (file)
index 0000000..ffa8a10
--- /dev/null
@@ -0,0 +1,121 @@
+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);
+    }
+}
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactoryTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/utils/QNameFactoryTest.java
new file mode 100644 (file)
index 0000000..76d4ceb
--- /dev/null
@@ -0,0 +1,29 @@
+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 static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class QNameFactoryTest {
+
+    @Test
+    public void testBasic(){
+        QName expected = TestModel.AUG_NAME_QNAME;
+        QName created = QNameFactory.create(expected.toString());
+
+        assertFalse( expected == created);
+
+        assertEquals(expected, created);
+
+        QName cached = QNameFactory.create(expected.toString());
+
+        assertEquals(expected, cached);
+
+        assertTrue( cached == created );
+    }
+
+}
index a42a66aed14d48423101e0667dc10ad3760258b4..31b658d1d7ea6f618f8277e4c5d214124d4613d6 100644 (file)
   <description>Configuration files for md-sal clustering</description>
   <packaging>jar</packaging>
   <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/initial/05-clustering.xml.conf</file>
+                  <type>xml</type>
+                  <classifier>config</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
   </build>
 </project>
index 5bf231dbe1ca31040565bad6b82d90201a4c0df2..0535179aadf79c4196a8f606433c1cd8b4e89949 100644 (file)
@@ -25,7 +25,7 @@ odl-cluster-data {
     }
 
     cluster {
-      seed-nodes = ["akka.tcp://opendaylight-cluster-data@<CHANGE_ME>:2550"]
+      seed-nodes = ["akka.tcp://opendaylight-cluster-data@<CHANGE_SEED_IP>:2550"]
 
       auto-down-unreachable-after = 10s
     }
@@ -47,7 +47,7 @@ odl-cluster-rpc {
     }
 
     cluster {
-      seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@<CHANGE_ME>:2551"]
+      seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@<CHANGE_SEED_IP>:2551"]
 
       auto-down-unreachable-after = 10s
     }
index 940559ef895bf9cec406eee2fbe73a7617da581a..32e32f94eb34e59d5b956095235883a717d3f95b 100644 (file)
@@ -10,39 +10,114 @@ package org.opendaylight.controller.md.sal.common.api.data;
 import org.opendaylight.yangtools.concepts.Path;
 
 /**
- * A chain of transactions. Transactions in a chain need to be committed in sequence and each
- * transaction should see the effects of previous transactions as if they happened. A chain
- * makes no guarantees of atomicity, in fact transactions are committed as soon as possible.
+ * A chain of transactions. Transactions in a chain need to be committed in
+ * sequence and each transaction should see the effects of previous committed transactions
+ * as they occurred. A chain makes no guarantees of atomicity across the chained transactions -
+ * the transactions are committed as soon as possible in the order that they were submitted.
  *
+ * This behaviour is different from the default AsyncDataBroker, where a
+ * transaction is always created from the current global state, not taking into
+ * account any transactions previously committed by the calling thread. Due to
+ * the asynchronous nature of transaction submission this can lead to surprising
+ * results. If a thread executes the following sequence sufficiently quickly:
+ *
+ * AsyncWriteTransaction t1 = broker.newWriteOnlyTransaction();
+ * t1.put(id, data);
+ * t1.submit();
+ *
+ * AsyncReadTransaction t2 = broker.newReadOnlyTransaction();
+ * Optional<?> maybeData = t2.read(id).get();
+ *
+ * it may happen, that it sees maybeData.isPresent() == false, simply because
+ * t1 has not completed the processes of being applied and t2 is actually
+ * allocated from the previous state. This is obviously bad for users who create
+ * incremental state in the datastore and actually read what they write in
+ * subsequent transactions.
+ *
+ * Using a TransactionChain instead of a broker solves this particular problem,
+ * and leads to expected behavior: t2 will always see the data written in t1
+ * present.
  */
-public interface TransactionChain<P extends Path<P>, D> extends AutoCloseable, AsyncDataTransactionFactory<P, D> {
+public interface TransactionChain<P extends Path<P>, D> extends AutoCloseable,
+        AsyncDataTransactionFactory<P, D> {
 
     /**
      * Create a new read only transaction which will continue the chain.
-     * The previous read-write transaction has to be either COMMITED or CANCELLED.
+     *
+     * <p>
+     * The previous write transaction has to be either SUBMITTED
+     * ({@link AsyncWriteTransaction#submit submit} was invoked) or CANCELLED
+     * ({@link #close close} was invoked).
+     * <p>
+     * The returned read-only transaction presents an isolated view of the data if the previous
+     * write transaction was successful - in other words, this read-only transaction will see the
+     * state changes made by the previous write transaction in the chain. However, state which
+     * was introduced by other transactions outside this transaction chain after creation of
+     * the previous transaction is not visible.
      *
      * @return New transaction in the chain.
-     * @throws IllegalStateException if the previous transaction was not COMMITED
-     *    or CANCELLED.
-     * @throws TransactionChainClosedException if the chain has been closed.
+     * @throws IllegalStateException
+     *             if the previous transaction was not SUBMITTED or CANCELLED.
+     * @throws TransactionChainClosedException
+     *             if the chain has been closed.
      */
     @Override
     public AsyncReadOnlyTransaction<P, D> newReadOnlyTransaction();
 
-
     /**
-     * Create a new read write transaction which will continue the chain.
-     * The previous read-write transaction has to be either COMMITED or CANCELLED.
+     * Create a new read-write transaction which will continue the chain.
+     *
+     * <p>
+     * The previous write transaction has to be either SUBMITTED
+     * ({@link AsyncWriteTransaction#submit submit} was invoked) or CANCELLED
+     * ({@link #close close} was invoked).
+     * <p>
+     * The returned read-write transaction presents an isolated view of the data if the previous
+     * write transaction was successful - in other words, this read-write transaction will see the
+     * state changes made by the previous write transaction in the chain. However, state which
+     * was introduced by other transactions outside this transaction chain after creation of
+     * the previous transaction is not visible.
+     * <p>
+     * Committing this read-write transaction using {@link AsyncWriteTransaction#submit submit}
+     * will submit the state changes in this transaction to be visible to any subsequent
+     * transaction in this chain and also to any transaction outside this chain.
      *
      * @return New transaction in the chain.
-     * @throws IllegalStateException if the previous transaction was not COMMITTED
-     *    or CANCELLED.
-     * @throws TransactionChainClosedException if the chain has been closed.
+     * @throws IllegalStateException
+     *             if the previous transaction was not SUBMITTED or CANCELLED.
+     * @throws TransactionChainClosedException
+     *             if the chain has been closed.
      */
     @Override
     public AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
 
+    /**
+     * Create a new write-only transaction which will continue the chain.
+     *
+     * <p>
+     * The previous write transaction has to be either SUBMITTED
+     * ({@link AsyncWriteTransaction#submit submit} was invoked) or CANCELLED
+     * ({@link #close close} was invoked).
+     * <p>
+     * The returned write-only transaction presents an isolated view of the data if the previous
+     * write transaction was successful - in other words, this write-only transaction will see the
+     * state changes made by the previous write transaction in the chain. However, state which
+     * was introduced by other transactions outside this transaction chain after creation of
+     * the previous transaction is not visible.
+     * <p>
+     * Committing this write-only transaction using {@link AsyncWriteTransaction#submit submit}
+     * will submit the state changes in this transaction to be visible to any subsequent
+     * transaction in this chain and also to any transaction outside this chain.
+     *
+     * @return New transaction in the chain.
+     * @throws IllegalStateException
+     *             if the previous transaction was not SUBMITTED or CANCELLED.
+     * @throws TransactionChainClosedException
+     *             if the chain has been closed.
+     */
+    @Override
+    public AsyncWriteTransaction<P, D> newWriteOnlyTransaction();
+
     @Override
     void close();
 }
-
index 94d21f5fd6bb02736a360592dc6826a3c70e4ae4..470e6110047adb93014455ae679dc8126b7e1dd3 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.yangtools.concepts.Path;
  * Interface for creating transaction chains.
  */
 public interface TransactionChainFactory<P extends Path<P>, D> {
+
     /**
      * Create a new transaction chain. The chain will be initialized to read
      * from its backing datastore, with no outstanding transaction. Listener
index c4ec760b40cd57d54579144f010b5e0f7425363e..76bbef713c350ad975c9dbb256bdef83bd1e4915 100644 (file)
@@ -36,13 +36,13 @@ public class TransactionChainProxy implements DOMStoreTransactionChain{
     @Override
     public DOMStoreReadWriteTransaction newReadWriteTransaction() {
         return new TransactionProxy(actorContext,
-            TransactionProxy.TransactionType.WRITE_ONLY, schemaContext);
+            TransactionProxy.TransactionType.READ_WRITE, schemaContext);
     }
 
     @Override
     public DOMStoreWriteTransaction newWriteOnlyTransaction() {
         return new TransactionProxy(actorContext,
-            TransactionProxy.TransactionType.READ_WRITE, schemaContext);
+            TransactionProxy.TransactionType.WRITE_ONLY, schemaContext);
     }
 
     @Override
index 6d7cbc86233543338a6b474a4a21035f33ecf770..2e7b2feb85bd97c7b80d09b8156f4b44c6fb343e 100644 (file)
@@ -108,7 +108,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
         this.identifier = TransactionIdentifier.builder().memberName(memberName).counter(
                 counter.getAndIncrement()).build();
 
-        LOG.debug("Created txn {}", identifier);
+        LOG.debug("Created txn {} of type {}", identifier, transactionType);
 
     }
 
index f584467ee91b37f2b0866cb9a39556eba3c9ace8..f5a6a348415308377d755011b133796659d3f27d 100644 (file)
@@ -9,14 +9,13 @@
 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){
@@ -32,10 +31,10 @@ public class FindPrimary implements SerializableMessage{
 
   @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;
   }
 }
index 69502837bcc6c114a1daa98986006ed0bd206aab..a2f6701524a7f4d2f42a4ce93b4463d368414659 100644 (file)
@@ -8,10 +8,9 @@
 
 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) {
@@ -49,10 +48,10 @@ public class PrimaryFound implements SerializableMessage {
 
   @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;
   }
 }
index 057028c469416df2767a067ef5e36e4256babd35..731a5364db247d52642e31da6e105ea655793196 100644 (file)
@@ -9,10 +9,9 @@
 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;
 
@@ -42,10 +41,10 @@ public class PrimaryNotFound implements SerializableMessage {
 
   @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;
   }
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxyTest.java
new file mode 100644 (file)
index 0000000..9b70397
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *
+ *  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.cluster.datastore;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class TransactionChainProxyTest {
+    ActorContext actorContext = Mockito.mock(ActorContext.class);
+    SchemaContext schemaContext = Mockito.mock(SchemaContext.class);
+    @Test
+    public void testNewReadOnlyTransaction() throws Exception {
+
+     DOMStoreTransaction dst = new TransactionChainProxy(actorContext, schemaContext).newReadOnlyTransaction();
+         Assert.assertTrue(dst instanceof DOMStoreReadTransaction);
+
+    }
+
+    @Test
+    public void testNewReadWriteTransaction() throws Exception {
+        DOMStoreTransaction dst = new TransactionChainProxy(actorContext, schemaContext).newReadWriteTransaction();
+        Assert.assertTrue(dst instanceof DOMStoreReadWriteTransaction);
+
+    }
+
+    @Test
+    public void testNewWriteOnlyTransaction() throws Exception {
+        DOMStoreTransaction dst = new TransactionChainProxy(actorContext, schemaContext).newWriteOnlyTransaction();
+        Assert.assertTrue(dst instanceof DOMStoreWriteTransaction);
+
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void testClose() throws Exception {
+        new TransactionChainProxy(actorContext, schemaContext).close();
+    }
+}
index 5876c50d51380a865afead594618627e7347bf3f..b916fddca7796e90dca402f1a8b4ac6a26fe2837 100644 (file)
@@ -12,8 +12,6 @@ package org.opendaylight.controller.sal.core.spi.data;
  * sequence and each transaction must see the effects of previous transactions
  * as if they happened. A chain makes no guarantees of atomicity, in fact
  * transactions are committed as soon as possible.
- *
- *
  */
 public interface DOMStoreTransactionChain extends DOMStoreTransactionFactory, AutoCloseable {
 
@@ -35,7 +33,7 @@ public interface DOMStoreTransactionChain extends DOMStoreTransactionFactory, Au
      *             if the chain has been closed.
      */
     @Override
-    public DOMStoreReadTransaction newReadOnlyTransaction();
+    DOMStoreReadTransaction newReadOnlyTransaction();
 
     /**
      * Create a new read write transaction which will continue the chain. The
@@ -55,10 +53,10 @@ public interface DOMStoreTransactionChain extends DOMStoreTransactionFactory, Au
      *             if the chain has been closed.
      */
     @Override
-    public DOMStoreReadWriteTransaction newReadWriteTransaction();
+    DOMStoreReadWriteTransaction newReadWriteTransaction();
 
     /**
-     * Create a new read write transaction which will continue the chain. The
+     * Create a new write-only transaction which will continue the chain. The
      * previous read-write transaction has to be either READY or CANCELLED.
      *
      *
@@ -68,8 +66,7 @@ public interface DOMStoreTransactionChain extends DOMStoreTransactionFactory, Au
      *             if the chain has been closed.
      */
     @Override
-    public DOMStoreWriteTransaction newWriteOnlyTransaction();
-
+    DOMStoreWriteTransaction newWriteOnlyTransaction();
 
     /**
      * Closes Transaction Chain.
@@ -80,6 +77,5 @@ public interface DOMStoreTransactionChain extends DOMStoreTransactionFactory, Au
      * @throws IllegalStateException If any of the outstanding created transactions was not canceled or ready.
      */
     @Override
-    public void close();
-
+    void close();
 }
diff --git a/opendaylight/md-sal/sal-dom-xsql-config/pom.xml b/opendaylight/md-sal/sal-dom-xsql-config/pom.xml
new file mode 100644 (file)
index 0000000..077405f
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+ Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.\r
+\r
+ This program and the accompanying materials are made available under the\r
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ and is available at http://www.eclipse.org/legal/epl-v10.html\r
+--><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">\r
+\r
+  <modelVersion>4.0.0</modelVersion>\r
+\r
+  <parent>\r
+    <artifactId>sal-parent</artifactId>\r
+    <groupId>org.opendaylight.controller</groupId>\r
+    <version>1.1-SNAPSHOT</version>\r
+  </parent>\r
+  <artifactId>sal-dom-xsql-config</artifactId>\r
+  <groupId>org.opendaylight.controller</groupId>\r
+  <description>Configuration files for md-sal</description>\r
+  <packaging>jar</packaging>\r
+  <properties>\r
+      <!-- Optional TODO: Rename your configfile to taste -->\r
+      <configfile>04-xsql.xml</configfile>\r
+  </properties>\r
+  <build>\r
+    <plugins>\r
+        <plugin>\r
+        <groupId>org.codehaus.mojo</groupId>\r
+        <artifactId>build-helper-maven-plugin</artifactId>\r
+        <executions>\r
+          <execution>\r
+            <id>attach-artifacts</id>\r
+            <goals>\r
+              <goal>attach-artifact</goal>\r
+            </goals>\r
+            <phase>package</phase>\r
+            <configuration>\r
+              <artifacts>\r
+                <artifact>\r
+                  <file>${project.build.directory}/classes/${configfile}</file>\r
+                  <type>xml</type>\r
+                  <classifier>config</classifier>\r
+                </artifact>\r
+              </artifacts>\r
+            </configuration>\r
+          </execution>\r
+        </executions>\r
+      </plugin>\r
+    </plugins>\r
+  </build>\r
+  <scm>\r
+      <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
+      <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
+      <tag>HEAD</tag>\r
+      <url>https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=summary</url>\r
+   </scm>\r
+</project>\r
diff --git a/opendaylight/md-sal/sal-dom-xsql-config/src/main/resources/04-xsql.xml b/opendaylight/md-sal/sal-dom-xsql-config/src/main/resources/04-xsql.xml
new file mode 100644 (file)
index 0000000..d7d547d
--- /dev/null
@@ -0,0 +1,29 @@
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:XSQL="http://netconfcentral.org/ns/XSQL">
+                        XSQL:XSQL
+                    </type>
+                    <name>XSQL</name>
+                    <data-broker>
+                       <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                       <name>binding-data-broker</name>
+                    </data-broker>
+                    <async-data-broker>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+                        <name>inmemory-data-broker</name>
+                    </async-data-broker>
+                    <schema-service>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+                        <name>yang-schema-service</name>
+                    </schema-service>
+                </module>
+            </modules>
+        </data>
+    </configuration>
+    <required-capabilities>
+        <capability>http://netconfcentral.org/ns/XSQL?module=XSQL&amp;revision=2014-06-26</capability>
+    </required-capabilities>
+</snapshot>
index 129013378ea57c713304793248e1cdc2f2c0a6ce..7ad3b8201e182cff9b3820a9e029f697e4cdb950 100644 (file)
@@ -191,7 +191,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     }
 
     @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);
     }
index 44ee61c116a9a4c5f8f336890827fcfceea68075..2caa76d49dff02a34ad98232ccdc7db139f07f2c 100644 (file)
@@ -33,7 +33,7 @@ final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction
                                           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);
@@ -52,19 +52,21 @@ final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction
         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.");
 
index d6bfc0c3b69152fd560afd545f11ddfd0773862a..23b039c2542540fe39d7af70b8ea0b0129e11aa3 100644 (file)
@@ -115,6 +115,11 @@ public final class NetconfStateSchemas {
 
         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);
     }
 
index 451cad48169ea81869ef11047895010715f0e30f..10aec4ca2e85038cdc7ff21dd0ebd4dc4b6cddf6 100644 (file)
@@ -15,11 +15,9 @@ import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMap
 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;
@@ -50,6 +48,12 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 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);
@@ -193,8 +197,9 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open
                     @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));
                                 }
@@ -220,8 +225,9 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open
                     @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));
                                 }
index 0a48e6c67dc8cc290c2b81a1b0eb67c05ac7c618..8e9f9978c4dd837334b07db2d1f6c96764e0ede9 100644 (file)
@@ -173,8 +173,12 @@ public class ConfigPersisterActivator implements BundleActivator {
                         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);
                     }
index 87b3f837e8c43a25f74f78cfbdd0b425bd8d94e9..2aa5d15224be5efa4c4f6f56a2498eab9df5b4f7 100644 (file)
@@ -12,7 +12,7 @@ import io.netty.util.concurrent.Promise;
 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> {
@@ -32,7 +32,7 @@ final class SshClientChannelInitializer extends AbstractChannelInitializer<Netco
     @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);
index 6826b4a09ca6013f57c192ef07fcef3bdd7e7387..a9e8dbe86b06b76087c902521022ff06e239b870 100644 (file)
@@ -9,16 +9,16 @@
 package org.opendaylight.controller.netconf.it;
 
 import static java.util.Arrays.asList;
-import static org.mockito.Matchers.any;
+import static org.junit.Assert.assertTrue;
 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 com.google.common.collect.Lists;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
 import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.IOException;
 import java.io.InputStream;
@@ -26,12 +26,11 @@ import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 import junit.framework.Assert;
 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;
@@ -47,6 +46,7 @@ import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProduce
 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;
@@ -72,27 +72,27 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, getModuleFactories().toArray(
                 new ModuleFactory[0])));
 
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+        final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
         factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
 
         final NetconfServerDispatcher dispatchS = createDispatcher(factoriesListener);
-        ChannelFuture s = dispatchS.createLocalServer(NetconfConfigUtil.getNetconfLocalAddress());
-        s.await();
-        EventLoopGroup bossGroup  = new NioEventLoopGroup();
+        dispatchS.createLocalServer(NetconfConfigUtil.getNetconfLocalAddress()).await();
+        final EventLoopGroup bossGroup  = new NioEventLoopGroup();
         sshServer = NetconfSSHServer.start(tlsAddress.getPort(), NetconfConfigUtil.getNetconfLocalAddress(), getAuthProvider(), bossGroup);
     }
 
-    private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+    private NetconfServerDispatcher createDispatcher(final NetconfOperationServiceFactoryListenerImpl factoriesListener) {
         return super.createDispatcher(factoriesListener, NetconfITTest.getNetconfMonitoringListenerService(), commitNot);
     }
 
     @After
     public void tearDown() throws Exception {
-        sshServer.stop();
+        sshServer.close();
         commitNot.close();
+        sshServer.join();
     }
 
     private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
@@ -106,13 +106,13 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testSecure() throws Exception {
-        NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
+        final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
         try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration())) {
             NetconfMessage response = netconfClient.sendMessage(getConfig);
             Assert.assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
                     NetconfMessageUtil.isErrorMessage(response));
 
-            NetconfMessage gs = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc message-id=\"2\"\n" +
+            final NetconfMessage gs = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc message-id=\"2\"\n" +
                     "     xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
                     "    <get-schema xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
                     "        <identifier>config</identifier>\n" +
@@ -125,6 +125,41 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
         }
     }
 
+    /**
+     * Test all requests are handled properly and no mismatch occurs in listener
+     */
+    @Test(timeout = 3*60*1000)
+    public void testSecureStress() throws Exception {
+        final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration())) {
+
+            final AtomicInteger responseCounter = new AtomicInteger(0);
+            final List<Future<?>> futures = Lists.newArrayList();
+
+            final int requests = 1000;
+            for (int i = 0; i < requests; i++) {
+                final Future<NetconfMessage> netconfMessageFuture = netconfClient.sendRequest(getConfig);
+                futures.add(netconfMessageFuture);
+                netconfMessageFuture.addListener(new GenericFutureListener<Future<? super NetconfMessage>>() {
+                    @Override
+                    public void operationComplete(final Future<? super NetconfMessage> future) throws Exception {
+                        assertTrue("Request unsuccessful " + future.cause(), future.isSuccess());
+                        responseCounter.incrementAndGet();
+                    }
+                });
+            }
+
+            for (final Future<?> future : futures) {
+                future.await();
+            }
+
+            // Give future listeners some time to finish counter incrementation
+            Thread.sleep(5000);
+
+            org.junit.Assert.assertEquals(requests, responseCounter.get());
+        }
+    }
+
     public NetconfClientConfiguration getClientConfiguration() throws IOException {
         final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
         b.withAddress(tlsAddress);
@@ -137,23 +172,13 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
     }
 
     public AuthProvider getAuthProvider() throws Exception {
-        AuthProvider mock = mock(AuthProviderImpl.class);
+        final AuthProvider mock = mock(AuthProviderImpl.class);
         doReturn(true).when(mock).authenticated(anyString(), anyString());
         doReturn(PEMGenerator.generate().toCharArray()).when(mock).getPEMAsCharArray();
         return mock;
     }
 
     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");
     }
 }
index fa78fa4bd3983c7eee4cb166e54bc5692f0bad54..3b3f71b0ed0f3aad635d88d6b0bb93a3e4229aa3 100644 (file)
@@ -7,8 +7,7 @@
  */
 package org.opendaylight.controller.netconf.monitoring;
 
-import com.google.common.collect.Maps;
-
+import java.util.Collections;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
@@ -18,36 +17,26 @@ import org.opendaylight.controller.netconf.monitoring.xml.JaxBSerializer;
 import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import java.util.Map;
-
 public class Get extends AbstractNetconfOperation {
 
     private static final Logger logger = LoggerFactory.getLogger(Get.class);
     private final NetconfMonitoringService netconfMonitor;
 
-    public Get(NetconfMonitoringService netconfMonitor) {
+    public Get(final NetconfMonitoringService netconfMonitor) {
         super(MonitoringConstants.MODULE_NAME);
         this.netconfMonitor = netconfMonitor;
     }
 
-    private Element getPlaceholder(Document innerResult) throws NetconfDocumentedException {
-        try {
-            XmlElement rootElement = null;
-            rootElement = XmlElement.fromDomElementWithExpected(innerResult.getDocumentElement(),
-                    XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
-            return rootElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY).getDomElement();
-        } catch (RuntimeException e) {
-            throw new IllegalArgumentException(String.format(
-                    "Input xml in wrong format, Expecting root element %s with child element %s, but was %s",
-                    XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.DATA_KEY,
-                    XmlUtil.toString(innerResult.getDocumentElement())), e);
-        }
+    private Element getPlaceholder(final Document innerResult)
+            throws NetconfDocumentedException {
+        final XmlElement rootElement = XmlElement.fromDomElementWithExpected(
+                innerResult.getDocumentElement(), XmlNetconfConstants.RPC_REPLY_KEY, XmlNetconfConstants.RFC4741_TARGET_NAMESPACE);
+        return rootElement.getOnlyChildElement(XmlNetconfConstants.DATA_KEY).getDomElement();
     }
 
     @Override
@@ -61,7 +50,7 @@ public class Get extends AbstractNetconfOperation {
     }
 
     @Override
-    public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation)
+    public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation)
             throws NetconfDocumentedException {
         if (subsequentOperation.isExecutionTermination()){
             throw new NetconfDocumentedException(String.format("Subsequent netconf operation expected by %s", this),
@@ -71,29 +60,29 @@ public class Get extends AbstractNetconfOperation {
         }
 
         try {
-            Document innerResult = subsequentOperation.execute(requestMessage);
+            final Document innerResult = subsequentOperation.execute(requestMessage);
 
-            NetconfState netconfMonitoring = new NetconfState(netconfMonitor);
+            final NetconfState netconfMonitoring = new NetconfState(netconfMonitor);
             Element monitoringXmlElement = new JaxBSerializer().toXml(netconfMonitoring);
 
             monitoringXmlElement = (Element) innerResult.importNode(monitoringXmlElement, true);
-            Element monitoringXmlElementPlaceholder = getPlaceholder(innerResult);
+            final Element monitoringXmlElementPlaceholder = getPlaceholder(innerResult);
             monitoringXmlElementPlaceholder.appendChild(monitoringXmlElement);
 
             return innerResult;
-        } catch (RuntimeException e) {
-            String errorMessage = "Get operation for netconf-state subtree failed";
+        } catch (final RuntimeException e) {
+            final String errorMessage = "Get operation for netconf-state subtree failed";
             logger.warn(errorMessage, e);
-            Map<String, String> info = Maps.newHashMap();
-            info.put(NetconfDocumentedException.ErrorSeverity.error.toString(), e.getMessage());
+
             throw new NetconfDocumentedException(errorMessage, NetconfDocumentedException.ErrorType.application,
                     NetconfDocumentedException.ErrorTag.operation_failed,
-                    NetconfDocumentedException.ErrorSeverity.error, info);
+                    NetconfDocumentedException.ErrorSeverity.error,
+                    Collections.singletonMap(NetconfDocumentedException.ErrorSeverity.error.toString(), e.getMessage()));
         }
     }
 
     @Override
-    protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation)
+    protected Element handle(final Document document, final XmlElement message, final NetconfOperationChainedExecution subsequentOperation)
             throws NetconfDocumentedException {
         throw new UnsupportedOperationException("Never gets called");
     }
index 14c47352a8409d633dca64a01db06759ad79f8f6..9d332c644029ff3c26a2725703e4b348ff046cf0 100644 (file)
@@ -24,7 +24,6 @@ public class NetconfMonitoringActivator implements BundleActivator {
     public void start(final BundleContext context)  {
         monitor = new NetconfMonitoringServiceTracker(context);
         monitor.open();
-
     }
 
     @Override
index 920236b9b67ab0a277a5e166459463bc3ebac562..f99ae54e6dafac6e9ea01f36e85ab46261d9ce67 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.netconf.monitoring.osgi;
 
 import com.google.common.base.Preconditions;
+import java.util.Hashtable;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.osgi.framework.BundleContext;
@@ -17,43 +18,39 @@ import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Dictionary;
-import java.util.Hashtable;
-
 public class NetconfMonitoringServiceTracker extends ServiceTracker<NetconfMonitoringService, NetconfMonitoringService> {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfMonitoringServiceTracker.class);
 
     private ServiceRegistration<NetconfOperationServiceFactory> reg;
 
-    NetconfMonitoringServiceTracker(BundleContext context) {
+    NetconfMonitoringServiceTracker(final BundleContext context) {
         super(context, NetconfMonitoringService.class, null);
     }
 
     @Override
-    public NetconfMonitoringService addingService(ServiceReference<NetconfMonitoringService> reference) {
+    public NetconfMonitoringService addingService(final ServiceReference<NetconfMonitoringService> reference) {
         Preconditions.checkState(reg == null, "Monitoring service was already added");
 
-        NetconfMonitoringService netconfMonitoringService = super.addingService(reference);
+        final NetconfMonitoringService netconfMonitoringService = super.addingService(reference);
 
         final NetconfMonitoringOperationService operationService = new NetconfMonitoringOperationService(
                 netconfMonitoringService);
-        NetconfOperationServiceFactory factory = new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
+        final NetconfOperationServiceFactory factory = new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
                 operationService);
 
-        Dictionary<String, ?> props = new Hashtable<>();
-        reg = context.registerService(NetconfOperationServiceFactory.class, factory, props);
+        reg = context.registerService(NetconfOperationServiceFactory.class, factory, new Hashtable<String, Object>());
 
         return netconfMonitoringService;
     }
 
     @Override
-    public void removedService(ServiceReference<NetconfMonitoringService> reference,
-            NetconfMonitoringService netconfMonitoringService) {
+    public void removedService(final ServiceReference<NetconfMonitoringService> reference,
+            final NetconfMonitoringService netconfMonitoringService) {
         if(reg!=null) {
             try {
                 reg.unregister();
-            } catch (Exception e) {
+            } catch (final Exception e) {
                 logger.warn("Ignoring exception while unregistering {}", reg, e);
             }
         }
index 4b07ab090aabfd3727524d255319352747839f4a..962ad17b66c280c5e7fb68cfc279ff30d79c2285 100644 (file)
@@ -18,17 +18,17 @@ import javax.xml.transform.dom.DOMResult;
 
 public class JaxBSerializer {
 
-    public Element toXml(NetconfState monitoringModel) {
-        DOMResult res = null;
+    public Element toXml(final NetconfState monitoringModel) {
+        final DOMResult res;
         try {
-            JAXBContext jaxbContext = JAXBContext.newInstance(NetconfState.class);
-            Marshaller marshaller = jaxbContext.createMarshaller();
+            final JAXBContext jaxbContext = JAXBContext.newInstance(NetconfState.class);
+            final Marshaller marshaller = jaxbContext.createMarshaller();
 
             marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
 
             res = new DOMResult();
             marshaller.marshal(monitoringModel, res);
-        } catch (JAXBException e) {
+        } catch (final JAXBException e) {
            throw new RuntimeException("Unable to serialize netconf state " + monitoringModel, e);
         }
         return ((Document)res.getNode()).getDocumentElement();
index 98bda5833e00a83487d9d356a44f0b55db0e82d9..8f5a1c029d8611b9f75c7b4570fc63002d9f1e18 100644 (file)
@@ -28,15 +28,12 @@ public final class NetconfState {
     private Schemas schemas;
     private Sessions sessions;
 
-    public NetconfState(NetconfMonitoringService monitoringService) {
+    public NetconfState(final NetconfMonitoringService monitoringService) {
         this.sessions = monitoringService.getSessions();
         this.schemas = monitoringService.getSchemas();
     }
 
-    public NetconfState() {
-    }
-
-
+    public NetconfState() {}
 
     @XmlElementWrapper(name="schemas")
     @XmlElement(name="schema")
@@ -44,7 +41,7 @@ public final class NetconfState {
         return Collections2.transform(schemas.getSchema(), new Function<Schema, MonitoringSchema>() {
             @Nullable
             @Override
-            public MonitoringSchema apply(@Nullable Schema input) {
+            public MonitoringSchema apply(@Nullable final Schema input) {
                 return new MonitoringSchema(input);
             }
         });
@@ -56,7 +53,7 @@ public final class NetconfState {
         return Collections2.transform(sessions.getSession(), new Function<Session, MonitoringSession>() {
             @Nullable
             @Override
-            public MonitoringSession apply(@Nullable Session input) {
+            public MonitoringSession apply(@Nullable final Session input) {
                 return new MonitoringSession(input);
             }
         });
diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/GetTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/GetTest.java
new file mode 100644 (file)
index 0000000..5fceac0
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.monitoring;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.fail;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+
+import java.util.Collections;
+import org.hamcrest.CoreMatchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SessionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
+import org.w3c.dom.Document;
+
+public class GetTest {
+
+    @Mock
+    private NetconfMonitoringService monitor;
+    @Mock
+    private Document request;
+    @Mock
+    private NetconfOperationChainedExecution subsequentOperation;
+    private Document incorrectSubsequentResult;
+    private Document correctSubsequentResult;
+
+    private Get get;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        incorrectSubsequentResult = XmlUtil.readXmlToDocument("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>");
+        correctSubsequentResult = XmlUtil.readXmlToDocument("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><data></data></rpc-reply>");
+
+        doReturn(new SessionsBuilder().setSession(Collections.<Session>emptyList()).build()).when(monitor).getSessions();
+        doReturn(new SchemasBuilder().setSchema(Collections.<Schema>emptyList()).build()).when(monitor).getSchemas();
+        doReturn(false).when(subsequentOperation).isExecutionTermination();
+
+        get = new Get(monitor);
+    }
+
+    @Test
+    public void testHandleNoSubsequent() throws Exception {
+        try {
+            get.handle(null, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+        } catch (final NetconfDocumentedException e) {
+            assertNetconfDocumentedEx(e, NetconfDocumentedException.ErrorSeverity.error, NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorType.application);
+            return;
+        }
+
+        fail("Get should fail without subsequent operation");
+    }
+
+    @Test
+    public void testHandleWrongPlaceholder() throws Exception {
+        doReturn(incorrectSubsequentResult).when(subsequentOperation).execute(request);
+        try {
+            get.handle(request, subsequentOperation);
+        } catch (final NetconfDocumentedException e) {
+            assertNetconfDocumentedEx(e, NetconfDocumentedException.ErrorSeverity.error, NetconfDocumentedException.ErrorTag.invalid_value, NetconfDocumentedException.ErrorType.application);
+            return;
+        }
+
+        fail("Get should fail with wrong xml");
+    }
+
+    @Test
+    public void testHandleRuntimeEx() throws Exception {
+        doThrow(RuntimeException.class).when(subsequentOperation).execute(request);
+        try {
+            get.handle(request, subsequentOperation);
+        } catch (final NetconfDocumentedException e) {
+            assertNetconfDocumentedEx(e, NetconfDocumentedException.ErrorSeverity.error, NetconfDocumentedException.ErrorTag.operation_failed, NetconfDocumentedException.ErrorType.application);
+            assertEquals(1, e.getErrorInfo().size());
+            return;
+        }
+
+        fail("Get should fail with wrong xml");
+    }
+
+    @Test
+    public void testSuccessHandle() throws Exception {
+        doReturn(correctSubsequentResult).when(subsequentOperation).execute(request);
+        assertTrue(get.getHandlingPriority().getPriority().get() > HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.getPriority().get());
+        final Document result = get.handle(request, subsequentOperation);
+        assertThat(XmlUtil.toString(result), CoreMatchers.containsString("sessions"));
+        assertThat(XmlUtil.toString(result), CoreMatchers.containsString("schemas"));
+
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testHandle() throws Exception {
+        get.handle(null, null, null);
+
+    }
+
+    private void assertNetconfDocumentedEx(final NetconfDocumentedException e, final NetconfDocumentedException.ErrorSeverity severity, final NetconfDocumentedException.ErrorTag errorTag, final NetconfDocumentedException.ErrorType type) {
+        assertEquals(severity, e.getErrorSeverity());
+        assertEquals(errorTag, e.getErrorTag());
+        assertEquals(type, e.getErrorType());
+    }
+}
index 02129574da40ec274a22b077614c38653a14770d..d0d587fb84263c02ef99cb0727de1d4c81b28223 100644 (file)
@@ -7,37 +7,40 @@
 */
 package org.opendaylight.controller.netconf.monitoring.xml;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
 import com.google.common.collect.Lists;
+import org.hamcrest.CoreMatchers;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SessionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.SchemaKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.DateAndTime;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.ZeroBasedCounter32;
-import org.w3c.dom.Element;
-
-import java.util.Date;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 
 public class JaxBSerializerTest {
 
     @Test
     public void testName() throws Exception {
 
-        NetconfMonitoringService service = new NetconfMonitoringService() {
+        final NetconfMonitoringService service = new NetconfMonitoringService() {
 
             @Override
             public Sessions getSessions() {
@@ -46,19 +49,54 @@ public class JaxBSerializerTest {
 
             @Override
             public Schemas getSchemas() {
-                return new SchemasBuilder().setSchema(Lists.<Schema>newArrayList()).build();
+                return new SchemasBuilder().setSchema(Lists.newArrayList(getMockSchema("id", "v1", Yang.class), getMockSchema("id2", "", Yang.class))).build();
             }
         };
-        NetconfState model = new NetconfState(service);
-        Element xml = new JaxBSerializer().toXml(model);
+        final NetconfState model = new NetconfState(service);
+        final String xml = XmlUtil.toString(new JaxBSerializer().toXml(model));
+
+        assertThat(xml, CoreMatchers.containsString(
+                "<schema>\n" +
+                "<format>yang</format>\n" +
+                "<identifier>id</identifier>\n" +
+                "<location>NETCONF</location>\n" +
+                "<namespace>localhost</namespace>\n" +
+                "<version>v1</version>\n" +
+                "</schema>\n"));
+
+        assertThat(xml, CoreMatchers.containsString(
+                "<session>\n" +
+                "<session-id>1</session-id>\n" +
+                "<in-bad-rpcs>0</in-bad-rpcs>\n" +
+                "<in-rpcs>0</in-rpcs>\n" +
+                "<login-time>loginTime</login-time>\n" +
+                "<out-notifications>0</out-notifications>\n" +
+                "<out-rpc-errors>0</out-rpc-errors>\n" +
+                "<ncme:session-identifier>client</ncme:session-identifier>\n" +
+                "<source-host>address/port</source-host>\n" +
+                "<transport>ncme:netconf-tcp</transport>\n" +
+                "<username>username</username>\n" +
+                "</session>"));
+    }
+
+    private Schema getMockSchema(final String id, final String version, final Class<Yang> format) {
+        final Schema mock = mock(Schema.class);
+
+        doReturn(format).when(mock).getFormat();
+        doReturn(id).when(mock).getIdentifier();
+        doReturn(new Uri("localhost")).when(mock).getNamespace();
+        doReturn(version).when(mock).getVersion();
+        doReturn(Lists.newArrayList(new Schema.Location(Schema.Location.Enumeration.NETCONF))).when(mock).getLocation();
+        doReturn(new SchemaKey(format, id, version)).when(mock).getKey();
+        return mock;
     }
 
-    private Session getMockSession(Class<? extends Transport> transportType) {
-        Session mocked = mock(Session.class);
-        Session1 mockedSession1 = mock(Session1.class);
+    private Session getMockSession(final Class<? extends Transport> transportType) {
+        final Session mocked = mock(Session.class);
+        final Session1 mockedSession1 = mock(Session1.class);
         doReturn("client").when(mockedSession1).getSessionIdentifier();
         doReturn(1L).when(mocked).getSessionId();
-        doReturn(new DateAndTime(new Date().toString())).when(mocked).getLoginTime();
+        doReturn(new DateAndTime("loginTime")).when(mocked).getLoginTime();
         doReturn(new Host(new DomainName("address/port"))).when(mocked).getSourceHost();
         doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInBadRpcs();
         doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInRpcs();
index 13041598d1a149932aa37e6efa8cb6e414decd87..cb8461a29965816320f1de6087e7a13629c4be9e 100644 (file)
       <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>
@@ -60,7 +64,6 @@
       <groupId>org.openexi</groupId>
       <artifactId>nagasena-rta</artifactId>
     </dependency>
-
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
       <groupId>xmlunit</groupId>
       <artifactId>xmlunit</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>mockito-configuration</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
@@ -82,7 +89,7 @@
         <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,
index d765ca8b2573702368ca9aca3e65212a8eed1e0a..f39e2c425d039cca549fd574607c52af02eced9e 100644 (file)
@@ -53,8 +53,7 @@ public final class NetconfHelloMessageToXMLEncoder extends NetconfMessageToXMLEn
         Optional<NetconfHelloMessageAdditionalHeader> headerOptional = ((NetconfHelloMessage) msg)
                 .getAdditionalHeader();
 
-        // If additional header present, serialize it along with netconf hello
-        // message
+        // If additional header present, serialize it along with netconf hello message
         if (headerOptional.isPresent()) {
             out.writeBytes(headerOptional.get().toFormattedString().getBytes(Charsets.UTF_8));
         }
index 69c0d53fc12144ad7e780126e5f8d3fe6372a571..bfc8d77e17bc7e4ae799d9b0859bdf3085f5e6af 100644 (file)
@@ -7,26 +7,21 @@
  */
 package org.opendaylight.controller.netconf.nettyutil.handler;
 
-import java.util.List;
-
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufInputStream;
 import io.netty.buffer.ByteBufUtil;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.ByteToMessageDecoder;
+import java.util.List;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
     private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
 
     @Override
-    @VisibleForTesting
     public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
 
         if (in.readableBytes() != 0) {
index b22b792d52980227d2aa85da39436535a19097b2..0548b1d371a415569dffc1826c02fae4700df45d 100644 (file)
@@ -8,13 +8,15 @@
 
 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;
 }
index b67aa0f96dcd53a084965fc3766399a26f2a5869..ab94e59a93dcf4e70494f7bf65ba66a28b5915c0 100644 (file)
@@ -8,13 +8,13 @@
 
 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;
 
 /**
  * Class Providing username/password authentication option to
- * {@link org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.SshHandler}
+ * {@link org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandler}
  */
 public class LoginPassword extends AuthenticationHandler {
     private final String username;
@@ -26,11 +26,13 @@ public class LoginPassword extends AuthenticationHandler {
     }
 
     @Override
-    public void authenticate(Connection connection) throws IOException {
-        boolean isAuthenticated = connection.authenticateWithPassword(username, password);
+    public String getUsername() {
+        return username;
+    }
 
-        if (!isAuthenticated) {
-            throw new IOException("Authentication failed.");
-        }
+    @Override
+    public AuthFuture authenticate(final ClientSession session) throws IOException {
+        session.addPasswordIdentity(password);
+        return session.auth();
     }
 }
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java
new file mode 100644 (file)
index 0000000..935cb8d
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * 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.ChannelOutboundHandler;
+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.IoOutputStream;
+import org.apache.sshd.common.io.IoReadFuture;
+import org.apache.sshd.common.io.IoWriteFuture;
+import org.apache.sshd.common.io.WritePendingException;
+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 SshWriteAsyncHandler sshWriteAsyncHandler;
+
+    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;
+
+        sshReadAsyncListener = new SshReadAsyncListener(ctx, channel.getAsyncOut());
+        sshWriteAsyncHandler = new SshWriteAsyncHandler(this, channel.getAsyncIn());
+
+        ctx.fireChannelActive();
+    }
+
+    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) {
+        sshWriteAsyncHandler.write(ctx, msg, promise);
+    }
+
+    private static void handleSshSessionClosed(final ChannelHandlerContext ctx) {
+        logger.debug("SSH session closed on channel: {}", ctx.channel());
+        ctx.fireChannelInactive();
+    }
+
+    @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) {
+        if(sshReadAsyncListener != null) {
+            sshReadAsyncListener.close();
+        }
+
+        if(sshWriteAsyncHandler != null) {
+            sshWriteAsyncHandler.close();
+        }
+
+        if(session!= null && !session.isClosed() && !session.isClosing()) {
+            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;
+        promise.setSuccess();
+
+        handleSshSessionClosed(ctx);
+    }
+
+    /**
+     * 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() {
+            // Remove self as listener on close to prevent reading from closed input
+            if(currentReadFuture != null) {
+                currentReadFuture.removeListener(this);
+            }
+
+            asyncOut = null;
+        }
+    }
+
+    private static final class SshWriteAsyncHandler implements AutoCloseable {
+        public static final int MAX_PENDING_WRITES = 100;
+
+        private final ChannelOutboundHandler channelHandler;
+        private IoOutputStream asyncIn;
+
+        // Counter that holds the amount of pending write messages
+        // Pending write can occur in case remote window is full
+        // In such case, we need to wait for the pending write to finish
+        private int pendingWriteCounter;
+        // Last write future, that can be pending
+        private IoWriteFuture lastWriteFuture;
+
+        public SshWriteAsyncHandler(final ChannelOutboundHandler channelHandler, final IoOutputStream asyncIn) {
+            this.channelHandler = channelHandler;
+            this.asyncIn = asyncIn;
+        }
+
+        public synchronized void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) {
+            try {
+                if(asyncIn.isClosed() || asyncIn.isClosing()) {
+                    handleSshSessionClosed(ctx);
+                } else {
+                    lastWriteFuture = asyncIn.write(toBuffer(msg));
+                    lastWriteFuture.addListener(new SshFutureListener<IoWriteFuture>() {
+
+                        @Override
+                        public void operationComplete(final IoWriteFuture future) {
+                            ((ByteBuf) msg).release();
+
+                            // Notify success or failure
+                            if (future.isWritten()) {
+                                promise.setSuccess();
+                            }
+                            promise.setFailure(future.getException());
+
+                            // Reset last pending future
+                            synchronized (SshWriteAsyncHandler.this) {
+                                lastWriteFuture = null;
+                            }
+                        }
+                    });
+                }
+            } catch (final WritePendingException e) {
+                // Check limit for pending writes
+                pendingWriteCounter++;
+                if(pendingWriteCounter > MAX_PENDING_WRITES) {
+                    handlePendingFailed(ctx, new IllegalStateException("Too much pending writes(" + MAX_PENDING_WRITES + ") on channel: " + ctx.channel() +
+                            ", remote window is not getting read or is too small"));
+                }
+
+                logger.debug("Write pending to SSH remote on channel: {}, current pending count: {}", ctx.channel(), pendingWriteCounter);
+
+                // In case of pending, re-invoke write after pending is finished
+                lastWriteFuture.addListener(new SshFutureListener<IoWriteFuture>() {
+                    @Override
+                    public void operationComplete(final IoWriteFuture future) {
+                        if(future.isWritten()) {
+                            synchronized (SshWriteAsyncHandler.this) {
+                                // Pending done, decrease counter
+                                pendingWriteCounter--;
+                            }
+                            write(ctx, msg, promise);
+                        } else {
+                            // Cannot reschedule pending, fail
+                            handlePendingFailed(ctx, e);
+                        }
+                    }
+
+                });
+            }
+        }
+
+        private void handlePendingFailed(final ChannelHandlerContext ctx, final Exception e) {
+            logger.warn("Exception while writing to SSH remote on channel {}", ctx.channel(), e);
+            try {
+                channelHandler.disconnect(ctx, ctx.newPromise());
+            } catch (final Exception ex) {
+                // This should not happen
+                throw new IllegalStateException(ex);
+            }
+        }
+
+        @Override
+        public void close() {
+            asyncIn = null;
+        }
+
+        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);
+        }
+
+    }
+}
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/Invoker.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/Invoker.java
deleted file mode 100644 (file)
index eab2546..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.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();
-                }
-            }
-        };
-    }
-}
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshClient.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshClient.java
deleted file mode 100644 (file)
index 271b781..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.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 +
-                '}';
-    }
-}
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshClientAdapter.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshClientAdapter.java
deleted file mode 100644 (file)
index 4ca7bdf..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.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 +
-                '}';
-    }
-}
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshHandler.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshHandler.java
deleted file mode 100644 (file)
index c710a01..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.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);
-    }
-}
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshSession.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshSession.java
deleted file mode 100644 (file)
index 9cdc592..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.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();
-        }
-    }
-}
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/ChannelInputStream.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/ChannelInputStream.java
deleted file mode 100644 (file)
index ba65b9e..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.nettyutil.handler.ssh.virtualsocket;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandler;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Class provides {@link InputStream} functionality to users of virtual socket.
- */
-public class ChannelInputStream extends InputStream implements ChannelInboundHandler {
-    private final Object lock = new Object();
-    private final ByteBuf bb = Unpooled.buffer();
-
-    @Override
-    public int read(byte b[], int off, int len) throws IOException {
-        if (b == null) {
-            throw new NullPointerException();
-        } else if (off < 0 || len < 0 || len > b.length - off) {
-            throw new IndexOutOfBoundsException();
-        } else if (len == 0) {
-            return 0;
-        }
-
-        int bytesRead = 1;
-        synchronized (lock) {
-            int c = read();
-
-            b[off] = (byte)c;
-
-            if(this.bb.readableBytes() == 0) {
-                return bytesRead;
-            }
-
-            int ltr = len-1;
-            ltr = (ltr <= bb.readableBytes()) ? ltr : bb.readableBytes();
-
-            bb.readBytes(b, 1, ltr);
-            bytesRead += ltr;
-        }
-        return bytesRead;
-    }
-
-    @Override
-    public int read() throws IOException {
-        synchronized (lock) {
-            while (this.bb.readableBytes() == 0) {
-                try {
-                    lock.wait();
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                    throw new IllegalStateException(e);
-                }
-            }
-            return this.bb.readByte() & 0xFF;
-        }
-    }
-
-    @Override
-    public int available() throws IOException {
-        synchronized (lock) {
-            return this.bb.readableBytes();
-        }
-    }
-
-    public void channelRegistered(ChannelHandlerContext ctx) {
-        ctx.fireChannelRegistered();
-    }
-
-    public void channelUnregistered(ChannelHandlerContext ctx) {
-        ctx.fireChannelUnregistered();
-    }
-
-    public void channelActive(ChannelHandlerContext ctx) {
-        ctx.fireChannelActive();
-    }
-
-    public void channelInactive(ChannelHandlerContext ctx) {
-        ctx.fireChannelInactive();
-    }
-
-    public void channelRead(ChannelHandlerContext ctx, Object o) {
-        synchronized(lock) {
-            this.bb.discardReadBytes();
-            this.bb.writeBytes((ByteBuf) o);
-            ((ByteBuf) o).release();
-            lock.notifyAll();
-        }
-    }
-
-    public void channelReadComplete(ChannelHandlerContext ctx) {
-        ctx.fireChannelReadComplete();
-    }
-
-    public void userEventTriggered(ChannelHandlerContext ctx, Object o) {
-        ctx.fireUserEventTriggered(o);
-    }
-
-    public void channelWritabilityChanged(ChannelHandlerContext ctx) {
-        ctx.fireChannelWritabilityChanged();
-    }
-
-    public void handlerAdded(ChannelHandlerContext ctx) {
-    }
-
-    public void handlerRemoved(ChannelHandlerContext ctx) {
-    }
-
-    public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
-        ctx.fireExceptionCaught(throwable);
-    }
-}
-
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/ChannelOutputStream.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/ChannelOutputStream.java
deleted file mode 100644 (file)
index 2dc5235..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.nettyutil.handler.ssh.virtualsocket;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelOutboundHandler;
-import io.netty.channel.ChannelPromise;
-
-import java.io.OutputStream;
-import java.net.SocketAddress;
-
-/**
- * Class provides {@link OutputStream) functionality to users of virtual socket.
- */
-public class ChannelOutputStream extends OutputStream implements ChannelOutboundHandler {
-    private final Object lock = new Object();
-    private ByteBuf buff = Unpooled.buffer();
-    private ChannelHandlerContext ctx;
-
-    @Override
-    public void flush() {
-        synchronized(lock) {
-            ctx.writeAndFlush(buff).awaitUninterruptibly();
-            buff = Unpooled.buffer();
-        }
-    }
-
-    @Override
-    public void write(int b) {
-        synchronized(lock) {
-            buff.writeByte(b);
-        }
-    }
-
-    public void bind(ChannelHandlerContext ctx, SocketAddress localAddress,
-                     ChannelPromise promise) {
-        ctx.bind(localAddress, promise);
-    }
-
-    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
-                        SocketAddress localAddress, ChannelPromise promise) {
-        this.ctx = ctx;
-        ctx.connect(remoteAddress, localAddress, promise);
-    }
-
-    public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
-        ctx.disconnect(promise);
-    }
-
-    public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
-        ctx.close(promise);
-    }
-
-    public void deregister(ChannelHandlerContext ctx, ChannelPromise channelPromise) {
-        ctx.deregister(channelPromise);
-    }
-
-    public void read(ChannelHandlerContext ctx) {
-        ctx.read();
-    }
-
-    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
-        // pass
-    }
-
-    public void flush(ChannelHandlerContext ctx) {
-        // pass
-    }
-
-    public void handlerAdded(ChannelHandlerContext ctx)
-            throws Exception {
-    }
-
-    public void handlerRemoved(ChannelHandlerContext ctx)
-            throws Exception {
-    }
-
-    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-        ctx.fireExceptionCaught(cause);
-    }
-}
diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/VirtualSocket.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/virtualsocket/VirtualSocket.java
deleted file mode 100644 (file)
index 69cce80..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.nettyutil.handler.ssh.virtualsocket;
-
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.nio.channels.SocketChannel;
-
-/**
- * Handler class providing Socket functionality to OIO client application. By using VirtualSocket user can
- * use OIO application in asynchronous environment and NIO EventLoop. Using VirtualSocket OIO applications
- * are able to use full potential of NIO environment.
- */
-//TODO: refactor - socket should be created when connection is established
-public class VirtualSocket extends Socket implements ChannelHandler {
-    private static final String INPUT_STREAM = "inputStream";
-    private static final String OUTPUT_STREAM = "outputStream";
-
-    private final ChannelInputStream chais = new ChannelInputStream();
-    private final ChannelOutputStream chaos = new ChannelOutputStream();
-    private ChannelHandlerContext ctx;
-
-
-    public InputStream getInputStream() {
-        return this.chais;
-    }
-
-    public OutputStream getOutputStream() {
-        return this.chaos;
-    }
-
-    public void handlerAdded(ChannelHandlerContext ctx) {
-        this.ctx = ctx;
-
-        if (ctx.channel().pipeline().get(OUTPUT_STREAM) == null) {
-            ctx.channel().pipeline().addFirst(OUTPUT_STREAM, chaos);
-        }
-
-        if (ctx.channel().pipeline().get(INPUT_STREAM) == null) {
-            ctx.channel().pipeline().addFirst(INPUT_STREAM, chais);
-        }
-    }
-
-    public void handlerRemoved(ChannelHandlerContext ctx) {
-        if (ctx.channel().pipeline().get(OUTPUT_STREAM) != null) {
-            ctx.channel().pipeline().remove(OUTPUT_STREAM);
-        }
-
-        if (ctx.channel().pipeline().get(INPUT_STREAM) != null) {
-            ctx.channel().pipeline().remove(INPUT_STREAM);
-        }
-    }
-
-    public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
-        // TODO exceptionCaught is deprecated transform this handler
-        ctx.fireExceptionCaught(throwable);
-    }
-
-
-    @Override
-    public void connect(SocketAddress endpoint) throws IOException {}
-
-    @Override
-    public void connect(SocketAddress endpoint, int timeout) throws IOException {}
-
-    @Override
-    public void bind(SocketAddress bindpoint) throws IOException {}
-
-    @Override
-    public InetAddress getInetAddress() {
-        InetSocketAddress isa = getInetSocketAddress();
-        return isa.getAddress();
-    }
-
-    @Override
-    public InetAddress getLocalAddress() {return null;}
-
-    @Override
-    public int getPort() {
-        return getInetSocketAddress().getPort();
-    }
-
-    private InetSocketAddress getInetSocketAddress() {
-        return (InetSocketAddress)getRemoteSocketAddress();
-    }
-
-    @Override
-    public int getLocalPort() {return -1;}
-
-    @Override
-    public SocketAddress getRemoteSocketAddress() {
-        return this.ctx.channel().remoteAddress();
-    }
-
-    @Override
-    public SocketAddress getLocalSocketAddress() {
-        return this.ctx.channel().localAddress();
-    }
-
-    @Override
-    public SocketChannel getChannel() {return null;}
-
-    @Override
-    public void setTcpNoDelay(boolean on) throws SocketException {}
-
-    @Override
-    public boolean getTcpNoDelay() throws SocketException {return false;}
-
-    @Override
-    public void setSoLinger(boolean on, int linger) throws SocketException {}
-
-    @Override
-    public int getSoLinger() throws SocketException {return -1;}
-
-    @Override
-    public void sendUrgentData(int data) throws IOException {}
-
-    @Override
-    public void setOOBInline(boolean on) throws SocketException {}
-
-    @Override
-    public boolean getOOBInline() throws SocketException {return false;}
-
-    @Override
-    public synchronized void setSoTimeout(int timeout) throws SocketException {}
-
-    @Override
-    public synchronized int getSoTimeout() throws SocketException {return -1;}
-
-    @Override
-    public synchronized void setSendBufferSize(int size) throws SocketException {}
-
-    @Override
-    public synchronized int getSendBufferSize() throws SocketException {return -1;}
-
-    @Override
-    public synchronized void setReceiveBufferSize(int size) throws SocketException {}
-
-    @Override
-    public synchronized int getReceiveBufferSize() throws SocketException {return -1;}
-
-    @Override
-    public void setKeepAlive(boolean on) throws SocketException {}
-
-    @Override
-    public boolean getKeepAlive() throws SocketException {return false;}
-
-    @Override
-    public void setTrafficClass(int tc) throws SocketException {}
-
-    @Override
-    public int getTrafficClass() throws SocketException {return -1;}
-
-    @Override
-    public void setReuseAddress(boolean on) throws SocketException {}
-
-    @Override
-    public boolean getReuseAddress() throws SocketException {return false;}
-
-    @Override
-    public synchronized void close() throws IOException {}
-
-    @Override
-    public void shutdownInput() throws IOException {}
-
-    @Override
-    public void shutdownOutput() throws IOException {}
-
-    @Override
-    public String toString() {
-        return "VirtualSocket{" + getInetAddress() + ":" + getPort() + "}";
-    }
-
-    @Override
-    public boolean isConnected() {return false;}
-
-    @Override
-    public boolean isBound() {return false;}
-
-    @Override
-    public boolean isClosed() {return false;}
-
-    @Override
-    public boolean isInputShutdown() {return false;}
-
-    @Override
-    public boolean isOutputShutdown() {return false;}
-
-    @Override
-    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {}
-}
diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ChunkedFramingMechanismEncoderTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ChunkedFramingMechanismEncoderTest.java
new file mode 100644 (file)
index 0000000..9347512
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.doAnswer;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
+
+public class ChunkedFramingMechanismEncoderTest {
+
+    private int chunkSize;
+    @Mock
+    private ChannelHandlerContext ctx;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        chunkSize = 256;
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegalSize() throws Exception {
+        new ChunkedFramingMechanismEncoder(10);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegalSizeMax() throws Exception {
+        new ChunkedFramingMechanismEncoder(Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void testEncode() throws Exception {
+        final List<ByteBuf> chunks = Lists.newArrayList();
+        doAnswer(new Answer() {
+            @Override
+            public Object answer(final InvocationOnMock invocation) throws Throwable {
+                chunks.add((ByteBuf) invocation.getArguments()[0]);
+                return null;
+            }
+        }).when(ctx).write(anyObject());
+
+        final ChunkedFramingMechanismEncoder encoder = new ChunkedFramingMechanismEncoder(chunkSize);
+        final int lastChunkSize = 20;
+        final ByteBuf src = Unpooled.wrappedBuffer(getByteArray(chunkSize * 4 + lastChunkSize));
+        final ByteBuf destination = Unpooled.buffer();
+        encoder.encode(ctx, src, destination);
+        assertEquals(4, chunks.size());
+
+        final int framingSize = "#256\n".getBytes().length + 1/* new line at end */;
+
+        for (final ByteBuf chunk : chunks) {
+            assertEquals(chunkSize + framingSize, chunk.readableBytes());
+        }
+
+        final int lastFramingSize = "#20\n".length() + NetconfMessageConstants.END_OF_CHUNK.length + 1/* new line at end */;
+        assertEquals(lastChunkSize + lastFramingSize, destination.readableBytes());
+    }
+
+    private byte[] getByteArray(final int size) {
+        final byte[] bytes = new byte[size];
+        for (int i = 0; i < size; i++) {
+            bytes[i] = 'a';
+        }
+        return bytes;
+    }
+}
diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/EOMFramingMechanismEncoderTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/EOMFramingMechanismEncoderTest.java
new file mode 100644 (file)
index 0000000..158f3a8
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.nettyutil.handler;
+
+import static org.junit.Assert.assertEquals;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
+
+public class EOMFramingMechanismEncoderTest {
+
+    @Test
+    public void testEncode() throws Exception {
+        final byte[] content = new byte[50];
+        final ByteBuf source = Unpooled.wrappedBuffer(content);
+        final ByteBuf destination = Unpooled.buffer();
+        new EOMFramingMechanismEncoder().encode(null, source, destination);
+
+        assertEquals(Unpooled.wrappedBuffer(source.array(), NetconfMessageConstants.END_OF_MESSAGE), destination);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/FramingMechanismHandlerFactoryTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/FramingMechanismHandlerFactoryTest.java
new file mode 100644 (file)
index 0000000..4f123f0
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
+
+public class FramingMechanismHandlerFactoryTest {
+
+    @Test
+    public void testCreate() throws Exception {
+        MatcherAssert.assertThat(FramingMechanismHandlerFactory
+                .createHandler(FramingMechanism.CHUNK), CoreMatchers
+                .instanceOf(ChunkedFramingMechanismEncoder.class));
+        MatcherAssert.assertThat(FramingMechanismHandlerFactory
+                .createHandler(FramingMechanism.EOM), CoreMatchers
+                .instanceOf(EOMFramingMechanismEncoder.class));
+    }
+}
\ No newline at end of file
index e088859e82a628a1fa166def6ae743f58e2d0045..a647b9ee172f44fc9e15baf7a284368ab00a8b19 100644 (file)
@@ -7,16 +7,16 @@
  */
 package org.opendaylight.controller.netconf.nettyutil.handler;
 
+import static org.junit.Assert.assertEquals;
+
 import com.google.common.base.Charsets;
 import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import junit.framework.Assert;
+import java.util.List;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import java.util.List;
-
 public class NetconfChunkAggregatorTest {
 
     private static final String CHUNKED_MESSAGE = "\n#4\n" +
@@ -45,26 +45,26 @@ public class NetconfChunkAggregatorTest {
 
     @Test
     public void testMultipleChunks() throws Exception {
-        List<Object> output = Lists.newArrayList();
-        ByteBuf input = Unpooled.copiedBuffer(CHUNKED_MESSAGE.getBytes(Charsets.UTF_8));
+        final List<Object> output = Lists.newArrayList();
+        final ByteBuf input = Unpooled.copiedBuffer(CHUNKED_MESSAGE.getBytes(Charsets.UTF_8));
         agr.decode(null, input, output);
 
-        Assert.assertEquals(1, output.size());
-        ByteBuf chunk = (ByteBuf) output.get(0);
+        assertEquals(1, output.size());
+        final ByteBuf chunk = (ByteBuf) output.get(0);
 
-        Assert.assertEquals(EXPECTED_MESSAGE, chunk.toString(Charsets.UTF_8));
+        assertEquals(EXPECTED_MESSAGE, chunk.toString(Charsets.UTF_8));
     }
 
     @Test
     public void testOneChunks() throws Exception {
-        List<Object> output = Lists.newArrayList();
-        ByteBuf input = Unpooled.copiedBuffer(CHUNKED_MESSAGE_ONE.getBytes(Charsets.UTF_8));
+        final List<Object> output = Lists.newArrayList();
+        final ByteBuf input = Unpooled.copiedBuffer(CHUNKED_MESSAGE_ONE.getBytes(Charsets.UTF_8));
         agr.decode(null, input, output);
 
-        Assert.assertEquals(1, output.size());
-        ByteBuf chunk = (ByteBuf) output.get(0);
+        assertEquals(1, output.size());
+        final ByteBuf chunk = (ByteBuf) output.get(0);
 
-        Assert.assertEquals(EXPECTED_MESSAGE, chunk.toString(Charsets.UTF_8));
+        assertEquals(EXPECTED_MESSAGE, chunk.toString(Charsets.UTF_8));
     }
 
 
diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfHelloMessageToXMLEncoderTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfHelloMessageToXMLEncoderTest.java
new file mode 100644 (file)
index 0000000..00d95df
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+
+public class NetconfHelloMessageToXMLEncoderTest {
+
+    @Mock
+    private ChannelHandlerContext ctx;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testEncode() throws Exception {
+        final NetconfMessage msg = new NetconfHelloMessage(XmlUtil.readXmlToDocument("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"),
+                NetconfHelloMessageAdditionalHeader.fromString("[tomas;10.0.0.0:10000;tcp;client;]"));
+        final ByteBuf destination = Unpooled.buffer();
+        new NetconfHelloMessageToXMLEncoder().encode(ctx, msg, destination);
+
+        final String encoded = new String(destination.array());
+        assertThat(encoded, containsString("[tomas;10.0.0.0:10000;tcp;client;]"));
+        assertThat(encoded, containsString("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"));
+    }
+
+    @Test
+    public void testEncodeNoHeader() throws Exception {
+        final NetconfMessage msg = new NetconfHelloMessage(XmlUtil.readXmlToDocument("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"));
+        final ByteBuf destination = Unpooled.buffer();
+        new NetconfHelloMessageToXMLEncoder().encode(ctx, msg, destination);
+
+        final String encoded = new String(destination.array());
+        assertThat(encoded, not(containsString("[tomas;10.0.0.0:10000;tcp;client;]")));
+        assertThat(encoded, containsString("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testEncodeNotHello() throws Exception {
+        final NetconfMessage msg = new NetconfMessage(XmlUtil.readXmlToDocument("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"));
+        new NetconfHelloMessageToXMLEncoder().encode(ctx, msg, null);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfXMLToHelloMessageDecoderTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfXMLToHelloMessageDecoderTest.java
new file mode 100644 (file)
index 0000000..f0c0d63
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.util.List;
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+
+public class NetconfXMLToHelloMessageDecoderTest {
+
+    @Test
+    public void testDecodeWithHeader() throws Exception {
+        final ByteBuf src = Unpooled.wrappedBuffer(String.format("%s\n%s",
+                "[tomas;10.0.0.0:10000;tcp;client;]", "<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>").getBytes());
+        final List<Object> out = Lists.newArrayList();
+        new NetconfXMLToHelloMessageDecoder().decode(null, src, out);
+
+        assertEquals(1, out.size());
+        assertThat(out.get(0), CoreMatchers.instanceOf(NetconfHelloMessage.class));
+        final NetconfHelloMessage hello = (NetconfHelloMessage) out.get(0);
+        assertTrue(hello.getAdditionalHeader().isPresent());
+        assertEquals("[tomas;10.0.0.0:10000;tcp;client;]\n", hello.getAdditionalHeader().get().toFormattedString());
+        assertThat(XmlUtil.toString(hello.getDocument()), CoreMatchers.containsString("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\""));
+    }
+
+    @Test
+    public void testDecodeNoHeader() throws Exception {
+        final ByteBuf src = Unpooled.wrappedBuffer("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>".getBytes());
+        final List<Object> out = Lists.newArrayList();
+        new NetconfXMLToHelloMessageDecoder().decode(null, src, out);
+
+        assertEquals(1, out.size());
+        assertThat(out.get(0), CoreMatchers.instanceOf(NetconfHelloMessage.class));
+        final NetconfHelloMessage hello = (NetconfHelloMessage) out.get(0);
+        assertFalse(hello.getAdditionalHeader().isPresent());
+    }
+
+    @Test
+    public void testDecodeCaching() throws Exception {
+        final ByteBuf msg1 = Unpooled.wrappedBuffer("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>".getBytes());
+        final ByteBuf msg2 = Unpooled.wrappedBuffer("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>".getBytes());
+        final ByteBuf src = Unpooled.wrappedBuffer("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>".getBytes());
+        final List<Object> out = Lists.newArrayList();
+        final NetconfXMLToHelloMessageDecoder decoder = new NetconfXMLToHelloMessageDecoder();
+        decoder.decode(null, src, out);
+        decoder.decode(null, msg1, out);
+        decoder.decode(null, msg2, out);
+
+        assertEquals(1, out.size());
+
+        assertEquals(2, Iterables.size(decoder.getPostHelloNetconfMessages()));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testDecodeNotHelloReceived() throws Exception {
+        final ByteBuf msg1 = Unpooled.wrappedBuffer("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>".getBytes());
+        final List<Object> out = Lists.newArrayList();
+        NetconfXMLToHelloMessageDecoder decoder = new NetconfXMLToHelloMessageDecoder();
+        decoder.decode(null, msg1, out);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfXMLToMessageDecoderTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfXMLToMessageDecoderTest.java
new file mode 100644 (file)
index 0000000..f85a387
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.Unpooled;
+import java.util.ArrayList;
+import org.junit.Test;
+
+public class NetconfXMLToMessageDecoderTest {
+
+    @Test
+    public void testDecodeNoMoreContent() throws Exception {
+        final ArrayList<Object> out = Lists.newArrayList();
+        new NetconfXMLToMessageDecoder().decode(null, Unpooled.buffer(), out);
+        assertEquals(0, out.size());
+    }
+
+    @Test
+    public void testDecode() throws Exception {
+        final ArrayList<Object> out = Lists.newArrayList();
+        new NetconfXMLToMessageDecoder().decode(null, Unpooled.wrappedBuffer("<msg/>".getBytes()), out);
+        assertEquals(1, out.size());
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/authentication/LoginPasswordTest.java b/opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/authentication/LoginPasswordTest.java
new file mode 100644 (file)
index 0000000..01df1e3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.authentication;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.client.future.AuthFuture;
+import org.junit.Test;
+
+public class LoginPasswordTest {
+
+    @Test
+    public void testLoginPassword() throws Exception {
+        final LoginPassword loginPassword = new LoginPassword("user", "pwd");
+        assertEquals("user", loginPassword.getUsername());
+
+        final ClientSession session = mock(ClientSession.class);
+        doNothing().when(session).addPasswordIdentity("pwd");
+        doReturn(mock(AuthFuture.class)).when(session).auth();
+        loginPassword.authenticate(session);
+
+        verify(session).addPasswordIdentity("pwd");
+        verify(session).auth();
+    }
+}
\ No newline at end of file
index febf3abf8e6fcbb6b035dfafffebb784e6392f44..8d48077f93174dbf211d4ac5be0568a9b6cfab9b 100644 (file)
       <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>
index 61297835a07b684dd009176c6c0e16c0971c2b5e..b32e880537e06d44571875a3dda56c4a36dddf6f 100644 (file)
@@ -29,7 +29,7 @@ import org.junit.Before;
 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;
@@ -94,7 +94,7 @@ public class SSHTest {
         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);
             }
         };
@@ -118,7 +118,7 @@ public class SSHTest {
             Thread.sleep(100);
         }
         assertFalse(echoClientHandler.isConnected());
-        assertEquals(State.FAILED_TO_CONNECT, echoClientHandler.getState());
+        assertEquals(State.CONNECTION_CLOSED, echoClientHandler.getState());
     }
 
 }
index 0a1da7760412edb0308b64d26ee83d92c51a8bee..69a57748ddabc88212411cf6b4ecf3d088a80381 100644 (file)
@@ -75,5 +75,5 @@ public interface INeutronLoadBalancerPoolMemberAware {
      *            instance of deleted LoadBalancerPool object
      * @return void
      */
-    public void NeutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+    public void neutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
 }
index 4a6a291e6a0a1518c68ee181c771139be5146ec5..d92c57bd8a59d9852326e2f2238af9dac2784971 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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,
@@ -57,6 +57,10 @@ public class Activator extends ComponentActivatorAbstractBase {
     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
@@ -136,6 +140,8 @@ public class Activator extends ComponentActivatorAbstractBase {
             // 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
@@ -165,6 +171,8 @@ public class Activator extends ComponentActivatorAbstractBase {
             // 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);
@@ -256,6 +264,8 @@ public class Activator extends ComponentActivatorAbstractBase {
             // 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(),
index b491c5fcea2e4b53914102a91e88a76591ac5d22..8b6d3c4a1cd7fc98d6820562e73068be331e7372 100644 (file)
@@ -1,11 +1,10 @@
 /*
- * 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;
 
 /**
@@ -34,8 +33,8 @@ public enum ActionType {
     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;
index 174f2546bad1039f87352b5e0a8bd129ad383732..ceb4553470933330516bd945652a07045dcf7e85 100644 (file)
@@ -1,6 +1,5 @@
-
 /*
- * 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,
@@ -20,7 +19,8 @@ public enum GlobalConstants {
     STATICVLAN("staticvlan"),
     CLUSTERINGSERVICES("clusteringservices"),
     STARTUPHOME("configuration/startup/"),
-    PROTOCOLPLUGINTYPE("protocolPluginType");
+    PROTOCOLPLUGINTYPE("protocolPluginType"),
+    PROTOCOLPLUGINPRIORITY("protocolPluginPriority");
 
     private GlobalConstants(String name) {
         this.name = name;
@@ -31,4 +31,4 @@ public enum GlobalConstants {
     public String toString() {
         return name;
     }
-}
\ No newline at end of file
+}
index 5c09a43feddf4cf66b2486d4d6df6776786b55a1..3fe9a18b3fa545cbdcf279092c272c43a34d4cc1 100644 (file)
@@ -1,12 +1,10 @@
-
 /*
- * 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;
@@ -176,8 +174,11 @@ public class ActionTest {
         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());
index e9039261a3724fb733f5a260300c291e9712224a..0c9ebab8c3c126a2442a0b8ef87ab30577602a10 100644 (file)
@@ -1,6 +1,5 @@
-
 /*
- * 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,
@@ -40,7 +39,6 @@ import org.opendaylight.controller.sal.packet.LinkEncap;
 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;
@@ -59,9 +57,9 @@ public class DataPacketService implements IPluginOutDataPacketService,
      * 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>();
 
     /**
@@ -186,11 +184,11 @@ public class DataPacketService implements IPluginOutDataPacketService,
                         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");
@@ -207,54 +205,11 @@ public class DataPacketService implements IPluginOutDataPacketService,
     }
 
     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) {
index 854125b3567a196b940556363ed56c82e99d50c0..60a7882bda552b5e2fa5fddfb7ebafad6d51ccbb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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,
@@ -38,7 +38,6 @@ import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerSe
 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;
@@ -58,12 +57,12 @@ public class FlowProgrammerService implements IFlowProgrammerService,
 
     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();
         /*
@@ -117,58 +116,11 @@ public class FlowProgrammerService implements IFlowProgrammerService,
 
     // 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) {
@@ -182,9 +134,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -193,9 +146,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -204,9 +158,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -215,9 +170,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -226,9 +182,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -237,9 +194,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -248,9 +206,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -508,9 +467,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
@@ -519,9 +479,10 @@ public class FlowProgrammerService implements IFlowProgrammerService,
     @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");
diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ProtocolService.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ProtocolService.java
new file mode 100644 (file)
index 0000000..e9dc2ad
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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();
+    }
+}
index 12de35f53677492581412017e9c763de96a05c0b..356c0e57c887f29f5d448ba523976f8fe077b5da 100644 (file)
@@ -1,6 +1,5 @@
-
 /*
- * 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,
@@ -43,7 +42,6 @@ import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 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;
@@ -60,8 +58,8 @@ import org.slf4j.LoggerFactory;
 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>();
 
@@ -107,58 +105,13 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
 
     // 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);
@@ -172,9 +125,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -184,9 +138,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -196,9 +151,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -208,9 +164,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -220,9 +177,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -232,9 +190,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -245,9 +204,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     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());
@@ -259,9 +219,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
             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());
@@ -271,9 +232,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -283,9 +245,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -297,9 +260,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     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());
@@ -310,9 +274,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     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());
@@ -322,9 +287,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     @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());
@@ -335,9 +301,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea
     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());
diff --git a/opendaylight/sal/implementation/src/test/java/org/opendaylight/controller/sal/implementation/ProtocolServiceTest.java b/opendaylight/sal/implementation/src/test/java/org/opendaylight/controller/sal/implementation/ProtocolServiceTest.java
new file mode 100644 (file)
index 0000000..079350b
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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 {
+}
index 6e7fd25e049a17fc997b30c5d2003227e1b9a61f..5e638cf9cc86c3bfbbeef4085cc0dabea51e8c64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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,
@@ -1191,7 +1191,7 @@ one.f.flows = {
             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() {
@@ -1207,7 +1207,7 @@ one.f.flows = {
             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() {
diff --git a/pom.xml b/pom.xml
index b81378e33f067d9025ff246a116cc64dd9993fb4..10c05e254f84d88d25f1e3e9b5ef3da3af84b7a1 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,7 @@
     <module>opendaylight/forwardingrulesmanager/implementation</module>
     <module>opendaylight/hosttracker/api</module>
     <module>opendaylight/hosttracker/implementation</module>
+    <module>opendaylight/hosttracker/shell</module>
     <module>opendaylight/hosttracker_new/api</module>
     <module>opendaylight/hosttracker_new/implementation</module>
     <module>opendaylight/containermanager/api</module>
     <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>