Merge "Bug: 627 Added RESTConf API Explorer that dynamically generates API documentat...
authorTony Tkacik <ttkacik@cisco.com>
Tue, 6 May 2014 06:52:40 +0000 (06:52 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 6 May 2014 06:52:40 +0000 (06:52 +0000)
163 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java
opendaylight/config/netconf-config-dispatcher/pom.xml [new file with mode: 0644]
opendaylight/config/netconf-config-dispatcher/src/main/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModule.java [new file with mode: 0644]
opendaylight/config/netconf-config-dispatcher/src/main/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleFactory.java [new file with mode: 0644]
opendaylight/config/netconf-config-dispatcher/src/main/yang/odl-netconf-cfg.yang [new file with mode: 0644]
opendaylight/config/netconf-config-dispatcher/src/main/yang/odl-netconfig-client-cfg.yang [new file with mode: 0644]
opendaylight/config/netty-config-api/src/main/yang/netty.yang
opendaylight/config/pom.xml
opendaylight/config/yang-jmx-generator-plugin/pom.xml
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/model/ModuleFieldSerializer.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.groovy [deleted file]
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.groovy [deleted file]
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/GenericGeneratedObjectFactory.groovy [deleted file]
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/GenericGeneratedObjectFactory.java [new file with mode: 0644]
opendaylight/config/yang-test-plugin/src/main/java/org/opendaylight/controller/config/yang/test/plugin/ProcessSources.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModule.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/DepTestImplModuleFactory.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleFactory.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModule.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleFactory.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/NetconfTestImplModuleUtil.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModule.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/TestImplModuleFactory.java
opendaylight/distribution/opendaylight-karaf/pom.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/context.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/00-netty.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/01-md-sal.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/02-clustering.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/03-toaster-sample.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/logback.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/tomcat-logging.properties [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/tomcat-server.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/custom.properties [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/src/main/resources/version.properties [new file with mode: 0644]
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-netconf-connector.xml [new file with mode: 0644]
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/04-netconf-connector.xml [deleted file]
opendaylight/md-sal/compatibility/flow-management-compatibility/pom.xml
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/ConfigurationReader.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend [deleted file]
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowCommitTransaction.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend [deleted file]
opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowManagementReader.java
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyCommitHandler.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyCommitHandler.xtend [deleted file]
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyProvider.xtend
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyTransaction.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/pom.xml
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractTransaction.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowCommitHandler.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransaction.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupCommitHandler.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransaction.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterCommitHandler.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransaction.xtend [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java
opendaylight/md-sal/inventory-manager/pom.xml
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java [new file with mode: 0644]
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend [deleted file]
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.java [new file with mode: 0644]
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.xtend [deleted file]
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryMapping.java [new file with mode: 0644]
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryMapping.xtend [deleted file]
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolderTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-dom-it/pom.xml
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentListenAugmentTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java
opendaylight/md-sal/sal-netconf-connector/pom.xml
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfRemoteSchemaSourceProvider.java
opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/decoding-exception/yang/number.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster/pom.xml
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/pom.xml
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java [deleted file]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcherImpl.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java [deleted file]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/TcpClientChannelInitializer.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfClientConfiguration.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfClientConfigurationBuilder.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfReconnectingClientConfiguration.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/test/TestingNetconfClient.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java
opendaylight/netconf/netconf-it/pom.xml
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/HardcodedYangStoreService.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/HandlingPriority.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSession.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfEXIToMessageDecoder.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/SendErrorExceptionUtil.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java
opendaylight/samples/loadbalancer/src/main/java/org/opendaylight/controller/samples/loadbalancer/entities/Pool.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
pom.xml

index a0db37df02b3fb1e307cf4e4d88dd15c6a53e5cb..c0fc4024ce5c090224cbcec8df6edc3821211834 100644 (file)
@@ -19,6 +19,7 @@
     <appauth.version>0.4.2-SNAPSHOT</appauth.version>
     <!-- Controller Modules Versions -->
     <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
+    <asm.version>4.1</asm.version>
     <!-- Plugin Versions -->
     <bouncycastle.version>1.50</bouncycastle.version>
     <bundle.plugin.version>2.3.7</bundle.plugin.version>
@@ -57,6 +58,7 @@
     <!-- OpenEXI third party lib for netconf-->
     <exi.nagasena.version>0000.0002.0038.0-SNAPSHOT</exi.nagasena.version>
     <failsafe.version>2.15</failsafe.version>
+    <feature.transaction.version>1.0.1</feature.transaction.version>
     <felix.dependencymanager.shell.version>3.0.1</felix.dependencymanager.shell.version>
     <felix.dependencymanager.version>3.1.0</felix.dependencymanager.version>
     <felix.fileinstall.version>3.1.6</felix.fileinstall.version>
@@ -92,6 +94,7 @@
     <jsr305.api.version>2.0.1</jsr305.api.version>
     <jsr311.api.version>1.1.1</jsr311.api.version>
     <junit.version>4.8.1</junit.version>
+    <karaf.version>3.0.1</karaf.version>
     <logback.version>1.0.9</logback.version>
     <logging.bridge.version>0.4.2-SNAPSHOT</logging.bridge.version>
     <maven.compile.plugin.version>2.5.1</maven.compile.plugin.version>
     <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
     <sonar.language>java</sonar.language>
     <sonar.skippedModules>org.openflow.openflowj,net.sf.jung2</sonar.skippedModules>
+    <spifly.version>1.0.0</spifly.version>
     <spring-osgi.version>1.2.1</spring-osgi.version>
+    <spring-security-karaf.version>3.1.4.RELEASE</spring-security-karaf.version>
     <spring-security.version>3.1.3.RELEASE</spring-security.version>
     <spring.version>3.1.3.RELEASE</spring.version>
     <statistics.northbound.version>0.4.2-SNAPSHOT</statistics.northbound.version>
         <artifactId>netconf-client</artifactId>
         <version>${netconf.version}</version>
       </dependency>
+
+      <!--Netconf config-->
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>netconf-config-dispatcher</artifactId>
+        <version>${netconf.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>netconf-impl</artifactId>
               <phase>generate-sources</phase>
               <configuration>
                 <sources>
+                  <source>src/main/yang</source>
                   <source>${jmxGeneratorPath}</source>
                   <source>${salGeneratorPath}</source>
                   <source>${xtend.dstdir}</source>
                     </goals>
                   </pluginExecutionFilter>
                   <action>
-                    <ignore></ignore>
+                    <execute></execute>
                   </action>
                 </pluginExecution>
                 <pluginExecution>
index 5e55cddf8e766509336041264dcecd7af06a2932..916ef9a88befa87ac8b5c17902ec6d970f23807d 100644 (file)
@@ -77,9 +77,6 @@ public abstract class AbstractDispatcher<S extends ProtocolSession<?>, L extends
      */
     protected ChannelFuture createServer(final InetSocketAddress address, final PipelineInitializer<S> initializer) {
         final ServerBootstrap b = new ServerBootstrap();
-        b.group(this.bossGroup, this.workerGroup);
-        b.channel(NioServerSocketChannel.class);
-        b.option(ChannelOption.SO_BACKLOG, 128);
         b.childHandler(new ChannelInitializer<SocketChannel>() {
 
             @Override
@@ -87,10 +84,20 @@ public abstract class AbstractDispatcher<S extends ProtocolSession<?>, L extends
                 initializer.initializeChannel(ch, new DefaultPromise<S>(executor));
             }
         });
-        b.childOption(ChannelOption.SO_KEEPALIVE, true);
 
+        b.option(ChannelOption.SO_BACKLOG, 128);
+        b.childOption(ChannelOption.SO_KEEPALIVE, true);
         customizeBootstrap(b);
 
+        if (b.group() == null) {
+            b.group(bossGroup, workerGroup);
+        }
+        try {
+            b.channel(NioServerSocketChannel.class);
+        } catch (IllegalStateException e) {
+            LOG.trace("Not overriding channelFactory on bootstrap {}", b, e);
+        }
+
         // Bind and start to accept incoming connections.
         final ChannelFuture f = b.bind(address);
         LOG.debug("Initiated server {} at {}.", f, address);
diff --git a/opendaylight/config/netconf-config-dispatcher/pom.xml b/opendaylight/config/netconf-config-dispatcher/pom.xml
new file mode 100644 (file)
index 0000000..65ebdaf
--- /dev/null
@@ -0,0 +1,52 @@
+<?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
+-->
+<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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-plugin-parent</artifactId>
+    <version>0.2.5-SNAPSHOT</version>
+    <relativePath>../config-plugin-parent</relativePath>
+  </parent>
+
+  <artifactId>netconf-config-dispatcher</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>config-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-client</artifactId>
+      <version>${netconf.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Export-Package>org.opendaylight.controller.config.yang.config.netconf,
+                      org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.netconf.rev140408,</Export-Package>
+            <Import-Package>*</Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/opendaylight/config/netconf-config-dispatcher/src/main/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModule.java b/opendaylight/config/netconf-config-dispatcher/src/main/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModule.java
new file mode 100644 (file)
index 0000000..344ef3d
--- /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.config.yang.config.netconf.client.dispatcher;
+
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+
+/**
+*
+*/
+public final class NetconfClientDispatcherModule extends org.opendaylight.controller.config.yang.config.netconf.client.dispatcher.AbstractNetconfClientDispatcherModule
+ {
+
+    public NetconfClientDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetconfClientDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            NetconfClientDispatcherModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation(){
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        return new NetconfClientDispatcherImpl(getBossThreadGroupDependency(), getWorkerThreadGroupDependency(), getTimerDependency());
+    }
+}
diff --git a/opendaylight/config/netconf-config-dispatcher/src/main/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleFactory.java b/opendaylight/config/netconf-config-dispatcher/src/main/java/org/opendaylight/controller/config/yang/config/netconf/client/dispatcher/NetconfClientDispatcherModuleFactory.java
new file mode 100644 (file)
index 0000000..cfd4ef6
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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.config.yang.config.netconf.client.dispatcher;
+
+/**
+*
+*/
+public class NetconfClientDispatcherModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.client.dispatcher.AbstractNetconfClientDispatcherModuleFactory
+{
+
+
+}
diff --git a/opendaylight/config/netconf-config-dispatcher/src/main/yang/odl-netconf-cfg.yang b/opendaylight/config/netconf-config-dispatcher/src/main/yang/odl-netconf-cfg.yang
new file mode 100644 (file)
index 0000000..16c2bcb
--- /dev/null
@@ -0,0 +1,31 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module odl-netconf-cfg {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf";
+    prefix "cfg-net";
+
+    import config { prefix config; revision-date 2013-04-05; }
+
+    description
+        "This module contains the base YANG definitions for
+        netconf related services.
+
+        Copyright (c)2013 Cisco Systems, Inc. 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";
+
+    revision "2014-04-08" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-client-dispatcher {
+
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.netconf.client.NetconfClientDispatcher";
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/config/netconf-config-dispatcher/src/main/yang/odl-netconfig-client-cfg.yang b/opendaylight/config/netconf-config-dispatcher/src/main/yang/odl-netconfig-client-cfg.yang
new file mode 100644 (file)
index 0000000..e00bdeb
--- /dev/null
@@ -0,0 +1,64 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module odl-netconfig-client-cfg {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher";
+    prefix "cfg-net-client";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; }
+    import netty {prefix netty; }
+
+    description
+        "This module contains the base YANG definitions for
+        netconf-client-dispatcher implementation.
+
+        Copyright (c)2013 Cisco Systems, Inc. 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";
+
+    revision "2014-04-08" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-client-dispatcher {
+            base config:module-type;
+            config:provided-service cfg-net:netconf-client-dispatcher;
+            config:java-name-prefix NetconfClientDispatcher;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netconf-client-dispatcher {
+            when "/config:modules/config:module/config:type = 'netconf-client-dispatcher'";
+
+            container boss-thread-group {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity netty:netty-threadgroup;
+                    }
+                }
+            }
+
+            container worker-thread-group {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity netty:netty-threadgroup;
+                    }
+                }
+            }
+
+            container timer {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity netty:netty-timer;
+                    }
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
index 7cac5ad5bc6202265be39f385b8749d61bc77e62..e274b058dccce43045ac6647d9c8775e65ceb78f 100644 (file)
@@ -49,4 +49,12 @@ module netty {
         base "config:service-type";
         config:java-class "io.netty.util.Timer";
     }
-}
\ No newline at end of file
+
+    identity channel-factory {
+        description
+            "Configuration wrapper around netty's channel factory";
+
+        base "config:service-type";
+        config:java-class "io.netty.bootstrap.ChannelFactory";
+    }
+}
index bd2924ad9dffc996cbea58b52d9f5b8ab1377850..20b1b411a4e93ee712f1a4e67844c57ceab630c8 100644 (file)
@@ -38,6 +38,7 @@
     <module>yang-test-plugin</module>
     <module>shutdown-api</module>
     <module>shutdown-impl</module>
+    <module>netconf-config-dispatcher</module>
     <module>config-module-archetype</module>
   </modules>
 
           <artifactId>gmaven-plugin</artifactId>
           <version>1.0</version>
         </plugin>
-        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
-        <plugin>
-          <groupId>org.eclipse.m2e</groupId>
-          <artifactId>lifecycle-mapping</artifactId>
-          <version>1.0.0</version>
-          <configuration>
-            <lifecycleMappingMetadata>
-              <pluginExecutions>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.opendaylight.yangtools</groupId>
-                    <artifactId>yang-maven-plugin</artifactId>
-                    <versionRange>[0.5.7-SNAPSHOT,)</versionRange>
-                    <goals>
-                      <goal>generate-sources</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
-              </pluginExecutions>
-            </lifecycleMappingMetadata>
-          </configuration>
-        </plugin>
         <plugin>
           <groupId>org.opendaylight.yangtools</groupId>
           <artifactId>yang-maven-plugin</artifactId>
index 2d49ed7fab1bb21b595d68d35683c8d9e7d7f85a..b8831f6979ec3205e496c13ee1df15217d3d9feb 100644 (file)
 
   </dependencies>
 
-  <build>
-    <plugins>
-      <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.1</version>
-        <configuration>
-          <compilerId>groovy-eclipse-compiler</compilerId>
-          <verbose>false</verbose>
-        </configuration>
-        <dependencies>
-
-          <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-eclipse-batch</artifactId>
-            <version>2.1.8-01</version>
-          </dependency>
-          <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-eclipse-compiler</artifactId>
-            <version>2.8.0-01</version>
-          </dependency>
-        </dependencies>
-      </plugin>
-
-    </plugins>
-  </build>
 </project>
index c0e3bc1ad84d6ab85b2010149b0286a01e440529..6211efe417973ee0f8faf637669e4f824a1df7f3 100644 (file)
@@ -16,7 +16,7 @@ public class ModuleFieldSerializer {
     public static String toString(ModuleField moduleField) {
         StringBuilder builder = new StringBuilder();
         builder.append("    ");
-        builder.append("protected final "
+        builder.append("public static final "
                 + JmxAttribute.class.getCanonicalName() + " "
                 + moduleField.getName() + "JmxAttribute = new "
                 + JmxAttribute.class.getCanonicalName() + "(\""
diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.groovy b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.groovy
deleted file mode 100644 (file)
index baff88c..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory
-import com.google.common.base.Optional
-import org.opendaylight.controller.config.api.DependencyResolver
-import org.opendaylight.controller.config.api.DynamicMBeanWithInstance
-import org.opendaylight.controller.config.api.ModuleIdentifier
-import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface
-import org.opendaylight.controller.config.api.annotations.Description
-import org.opendaylight.controller.config.spi.Module
-import org.opendaylight.controller.config.spi.ModuleFactory
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractFactoryTemplate
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.*
-import org.opendaylight.yangtools.yang.common.QName
-import org.osgi.framework.BundleContext
-
-public class AbsFactoryGeneratedObjectFactory {
-
-    public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
-        FullyQualifiedName absFactoryFQN = new FullyQualifiedName(mbe.packageName, mbe.abstractFactoryName)
-        FullyQualifiedName moduleFQN = new FullyQualifiedName(mbe.packageName, mbe.stubModuleName)
-        Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription())
-
-        AbstractFactoryTemplate abstractFactoryTemplate = TemplateFactory.abstractFactoryTemplateFromMbe(mbe)
-        Optional<String> header = abstractFactoryTemplate.headerString;
-        List<FullyQualifiedName> providedServices = mbe.providedServices.keySet().collect {
-            FullyQualifiedName.fromString(it)
-        }
-
-
-        return toGeneratedObject(absFactoryFQN, copyright,
-                header, classJavaDoc, mbe.yangModuleQName,
-                mbe.globallyUniqueName,
-                providedServices,
-                moduleFQN,
-                abstractFactoryTemplate.fields)
-    }
-
-    public GeneratedObject toGeneratedObject(FullyQualifiedName absFactoryFQN, Optional<String> copyright,
-                                             Optional<String> header, Optional<String> classJavaDoc, QName yangModuleQName,
-                                             String globallyUniqueName,
-                                             List<FullyQualifiedName> providedServices,
-                                             FullyQualifiedName moduleFQN,
-                                             List<Field> moduleFields) {
-        JavaFileInputBuilder b = new JavaFileInputBuilder()
-        Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName)
-        b.addClassAnnotation(moduleQNameAnnotation)
-
-        b.setFqn(absFactoryFQN)
-        b.setTypeName(TypeName.absClassType)
-
-        b.setCopyright(copyright);
-        b.setHeader(header);
-        b.setClassJavaDoc(classJavaDoc);
-        b.addImplementsFQN(new FullyQualifiedName(ModuleFactory))
-        if (classJavaDoc.isPresent()) {
-            b.addClassAnnotation("@${Description.canonicalName}(value=\"${classJavaDoc.get()}\")")
-        }
-
-        b.addToBody("public static final java.lang.String NAME = \"${globallyUniqueName}\";")
-        b.addToBody("private static final java.util.Set<Class<? extends ${AbstractServiceInterface.canonicalName}>> serviceIfcs;")
-
-        b.addToBody("@Override\n public final String getImplementationName() { \n return NAME; \n}")
-
-        b.addToBody(getServiceIfcsInitialization(providedServices))
-
-        // createModule
-        b.addToBody("""
-            @Override
-            public ${Module.canonicalName} createModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${BundleContext.canonicalName} bundleContext) {
-                return instantiateModule(instanceName, dependencyResolver, bundleContext);
-            }
-            """)
-
-        b.addToBody(getCreateModule(moduleFQN, moduleFields))
-
-        b.addToBody("""
-            public ${moduleFQN} instantiateModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${moduleFQN} oldModule, ${AutoCloseable.canonicalName} oldInstance, ${BundleContext.canonicalName} bundleContext) {
-                return new ${moduleFQN}(new ${ModuleIdentifier.canonicalName}(NAME, instanceName), dependencyResolver, oldModule, oldInstance);
-            }
-            """)
-
-        b.addToBody("""
-            public ${moduleFQN} instantiateModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${BundleContext.canonicalName} bundleContext) {
-                return new ${moduleFQN}(new ${ModuleIdentifier.canonicalName}(NAME, instanceName), dependencyResolver);
-            }
-            """)
-
-        b.addToBody("""
-            public ${moduleFQN} handleChangedClass(${DynamicMBeanWithInstance.canonicalName} old) throws Exception {
-                throw new UnsupportedOperationException("Class reloading is not supported");
-            }
-            """)
-
-        b.addToBody("""
-            @Override
-            public java.util.Set<${moduleFQN}> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, ${BundleContext.canonicalName} bundleContext) {
-                return new java.util.HashSet<${moduleFQN}>();
-            }
-            """)
-
-        return new GeneratedObjectBuilder(b.build()).toGeneratedObject()
-    }
-
-    private static String getCreateModule(FullyQualifiedName moduleFQN, List<Field> moduleFields) {
-        String result = """
-            @Override
-            public ${Module.canonicalName} createModule(String instanceName, ${DependencyResolver.canonicalName} dependencyResolver, ${DynamicMBeanWithInstance.canonicalName} old, ${BundleContext.canonicalName} bundleContext) throws Exception {
-                ${moduleFQN} oldModule = null;
-                try {
-                    oldModule = (${moduleFQN}) old.getModule();
-                } catch(Exception e) {
-                    return handleChangedClass(old);
-                }
-                ${moduleFQN} module = instantiateModule(instanceName, dependencyResolver, oldModule, old.getInstance(), bundleContext);
-            """
-        result += moduleFields.collect{"module.set${it.name}(oldModule.get${it.name}());"}.join("\n")
-        result += """
-                return module;
-            }
-            """
-        return result
-    }
-
-    private static String getServiceIfcsInitialization(List<FullyQualifiedName> providedServices) {
-        String generic = "Class<? extends ${AbstractServiceInterface.canonicalName}>"
-
-        String result = """static {
-            java.util.Set<${generic}> serviceIfcs2 = new java.util.HashSet<${generic}>();
-            """
-        result += providedServices.collect{"serviceIfcs2.add(${it}.class);"}.join("\n")
-        result += """serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);
-            }
-            """
-
-        // add isModuleImplementingServiceInterface and getImplementedServiceIntefaces methods
-
-        result += """
-            @Override
-            public final boolean isModuleImplementingServiceInterface(Class<? extends ${AbstractServiceInterface.canonicalName}> serviceInterface) {
-                for (Class<?> ifc: serviceIfcs) {
-                    if (serviceInterface.isAssignableFrom(ifc)){
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            public java.util.Set<Class<? extends ${AbstractServiceInterface.canonicalName}>> getImplementedServiceIntefaces() {
-                return serviceIfcs;
-            }
-            """
-
-        return result
-    }
-
-}
diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.java
new file mode 100644 (file)
index 0000000..48a6c15
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory;
+
+import static java.lang.String.format;
+
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
+import org.opendaylight.controller.config.api.annotations.Description;
+import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractFactoryTemplate;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.TypeName;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.osgi.framework.BundleContext;
+
+public class AbsFactoryGeneratedObjectFactory {
+
+    public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
+        FullyQualifiedName absFactoryFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractFactoryName());
+        FullyQualifiedName moduleFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getStubModuleName());
+        Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription());
+
+        AbstractFactoryTemplate abstractFactoryTemplate = TemplateFactory.abstractFactoryTemplateFromMbe(mbe);
+        Optional<String> header = abstractFactoryTemplate.getHeaderString();
+
+        List<FullyQualifiedName> providedServices = new ArrayList<>();
+        for(String providedService: mbe.getProvidedServices().keySet()) {
+            providedServices.add(FullyQualifiedName.fromString(providedService));
+        }
+
+        return toGeneratedObject(absFactoryFQN, copyright,
+                header, classJavaDoc, mbe.getYangModuleQName(),
+                mbe.getGloballyUniqueName(),
+                providedServices,
+                moduleFQN,
+                abstractFactoryTemplate.getFields());
+    }
+
+    public GeneratedObject toGeneratedObject(FullyQualifiedName absFactoryFQN, Optional<String> copyright,
+                                             Optional<String> header, Optional<String> classJavaDoc, QName yangModuleQName,
+                                             String globallyUniqueName,
+                                             List<FullyQualifiedName> providedServices,
+                                             FullyQualifiedName moduleFQN,
+                                             List<Field> moduleFields) {
+        JavaFileInputBuilder b = new JavaFileInputBuilder();
+        Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName);
+        b.addClassAnnotation(moduleQNameAnnotation);
+
+        b.setFqn(absFactoryFQN);
+        b.setTypeName(TypeName.absClassType);
+
+        b.setCopyright(copyright);
+        b.setHeader(header);
+        b.setClassJavaDoc(classJavaDoc);
+        b.addImplementsFQN(new FullyQualifiedName(ModuleFactory.class));
+        if (classJavaDoc.isPresent()) {
+            b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
+        }
+
+        b.addToBody(format("public static final java.lang.String NAME = \"%s\";", globallyUniqueName));
+        b.addToBody(format("private static final java.util.Set<Class<? extends %s>> serviceIfcs;",
+                AbstractServiceInterface.class.getCanonicalName()));
+
+        b.addToBody("@Override\n public final String getImplementationName() { \n return NAME; \n}");
+
+        b.addToBody(getServiceIfcsInitialization(providedServices));
+
+        // createModule
+        b.addToBody(format("\n"+
+            "@Override\n"+
+            "public %s createModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
+                "return instantiateModule(instanceName, dependencyResolver, bundleContext);\n"+
+            "}\n",
+                Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(), BundleContext.class.getCanonicalName()));
+
+        b.addToBody(getCreateModule(moduleFQN, moduleFields));
+
+        b.addToBody(format("\n"+
+            "public %s instantiateModule(String instanceName, %s dependencyResolver, %s oldModule, %s oldInstance, %s bundleContext) {\n"+
+                "return new %s(new %s(NAME, instanceName), dependencyResolver, oldModule, oldInstance);\n"+
+            "}\n",
+                moduleFQN, DependencyResolver.class.getCanonicalName(), moduleFQN, AutoCloseable.class.getCanonicalName(),
+                BundleContext.class.getCanonicalName(), moduleFQN, ModuleIdentifier.class.getCanonicalName()));
+
+        b.addToBody(format("\n"+
+            "public %s instantiateModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+
+                "return new %s(new %s(NAME, instanceName), dependencyResolver);\n"+
+            "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), BundleContext.class.getCanonicalName(),
+                moduleFQN, ModuleIdentifier.class.getCanonicalName()
+        ));
+
+        b.addToBody(format("\n"+
+            "public %s handleChangedClass(%s old) throws Exception {\n"+
+                "throw new UnsupportedOperationException(\"Class reloading is not supported\");\n"+
+            "}\n", moduleFQN, DynamicMBeanWithInstance.class.getCanonicalName()));
+
+        b.addToBody(format("\n"+
+            "@Override\n"+
+            "public java.util.Set<%s> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, %s bundleContext) {\n"+
+                "return new java.util.HashSet<%s>();\n"+
+            "}\n", moduleFQN, BundleContext.class.getCanonicalName(), moduleFQN));
+
+        return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
+    }
+
+    private static String getCreateModule(FullyQualifiedName moduleFQN, List<Field> moduleFields) {
+        String result = "\n"+
+            "@Override\n"+
+            format("public %s createModule(String instanceName, %s dependencyResolver, %s old, %s bundleContext) throws Exception {\n",
+                                Module.class.getCanonicalName(),DependencyResolver.class.getCanonicalName(),
+                                DynamicMBeanWithInstance.class.getCanonicalName(),BundleContext.class.getCanonicalName())+
+                format("%s oldModule = null;\n",moduleFQN)+
+                "try {\n"+
+                    format("oldModule = (%s) old.getModule();\n",moduleFQN)+
+                "} catch(Exception e) {\n"+
+                    "return handleChangedClass(old);\n"+
+                "}\n"+
+            format("%s module = instantiateModule(instanceName, dependencyResolver, oldModule, old.getInstance(), bundleContext);\n", moduleFQN);
+
+        for(Field field: moduleFields) {
+            result += format("module.set%s(oldModule.get%1$s());\n", field.getName());
+        }
+
+        result += "\n"+
+                "return module;\n"+
+            "}\n";
+        return result;
+    }
+
+    private static String getServiceIfcsInitialization(List<FullyQualifiedName> providedServices) {
+        String generic = format("Class<? extends %s>", AbstractServiceInterface.class.getCanonicalName());
+
+        String result = format("static {\n"+
+            "java.util.Set<%1$s> serviceIfcs2 = new java.util.HashSet<%1$s>();\n", generic);
+
+        for(FullyQualifiedName fqn: providedServices) {
+            result += format("serviceIfcs2.add(%s.class);\n", fqn);
+        }
+        result += "serviceIfcs = java.util.Collections.unmodifiableSet(serviceIfcs2);\n"+
+            "}\n";
+
+        // add isModuleImplementingServiceInterface and getImplementedServiceIntefaces methods
+
+        result += format("\n"+
+            "@Override\n"+
+            "public final boolean isModuleImplementingServiceInterface(Class<? extends %1$s> serviceInterface) {\n"+
+                "for (Class<?> ifc: serviceIfcs) {\n"+
+                    "if (serviceInterface.isAssignableFrom(ifc)){\n"+
+                        "return true;\n"+
+                    "}\n"+
+                "}\n"+
+                "return false;\n"+
+            "}\n"+
+            "\n"+
+            "@Override\n"+
+            "public java.util.Set<Class<? extends %1$s>> getImplementedServiceIntefaces() {\n"+
+                "return serviceIfcs;\n"+
+            "}\n", AbstractServiceInterface.class.getCanonicalName());
+
+        return result;
+    }
+
+}
diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.groovy b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.groovy
deleted file mode 100644 (file)
index 930acff..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory
-import com.google.common.base.Optional
-import org.opendaylight.controller.config.api.DependencyResolver
-import org.opendaylight.controller.config.api.ModuleIdentifier
-import org.opendaylight.controller.config.api.annotations.Description
-import org.opendaylight.controller.config.api.runtime.RootRuntimeBeanRegistrator
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractModuleTemplate
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.*
-import org.opendaylight.yangtools.yang.common.QName
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-public class AbsModuleGeneratedObjectFactory {
-
-    public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
-        FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName())
-        Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription())
-        AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe)
-        Optional<String> header = abstractModuleTemplate.headerString;
-        List<FullyQualifiedName> implementedInterfaces = abstractModuleTemplate.getTypeDeclaration().getImplemented().collect {
-            FullyQualifiedName.fromString(it)
-        }
-        Optional<FullyQualifiedName> maybeRegistratorType
-        if (abstractModuleTemplate.isRuntime()) {
-            maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType()))
-        } else {
-            maybeRegistratorType = Optional.absent()
-        }
-
-        return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces,
-                abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(),
-                mbe.yangModuleQName
-        )
-    }
-
-    public GeneratedObject toGeneratedObject(FullyQualifiedName abstractFQN,
-                                             Optional<String> copyright,
-                                             Optional<String> header,
-                                             Optional<String> classJavaDoc,
-                                             List<FullyQualifiedName> implementedInterfaces,
-                                             List<ModuleField> moduleFields,
-                                             Optional<FullyQualifiedName> maybeRegistratorType,
-                                             List<Method> methods,
-                                             QName yangModuleQName) {
-        JavaFileInputBuilder b = new JavaFileInputBuilder()
-
-        Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName)
-        b.addClassAnnotation(moduleQNameAnnotation)
-
-        b.setFqn(abstractFQN)
-        b.setTypeName(TypeName.absClassType)
-
-        b.setCopyright(copyright);
-        b.setHeader(header);
-        b.setClassJavaDoc(classJavaDoc);
-        implementedInterfaces.each { b.addImplementsFQN(it) }
-        if (classJavaDoc.isPresent()) {
-            b.addClassAnnotation("@${Description.canonicalName}(value=\"${classJavaDoc.get()}\")")
-        }
-
-        // add logger:
-        b.addToBody(getLogger(abstractFQN));
-
-        b.addToBody("//attributes start");
-
-        b.addToBody(moduleFields.collect { it.toString() }.join("\n"))
-
-        b.addToBody("//attributes end");
-
-
-        b.addToBody(getCommonFields(abstractFQN));
-
-
-        b.addToBody(getNewConstructor(abstractFQN))
-        b.addToBody(getCopyFromOldConstructor(abstractFQN))
-
-        b.addToBody(getRuntimeRegistratorCode(maybeRegistratorType))
-        b.addToBody(getValidationMethods(moduleFields))
-
-        b.addToBody(getCachesOfResolvedDependencies(moduleFields))
-        b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields))
-        b.addToBody(getGetInstance(moduleFields))
-        b.addToBody(getReuseLogic(moduleFields, abstractFQN))
-        b.addToBody(getEqualsAndHashCode(abstractFQN))
-
-        b.addToBody(getMethods(methods))
-
-        return new GeneratedObjectBuilder(b.build()).toGeneratedObject()
-    }
-
-    private static String getMethods(List<Method> methods) {
-        String result = """
-            // getters and setters
-        """
-        result += methods.collect{it.toString()}.join("\n")
-        return result
-    }
-
-    private static String getEqualsAndHashCode(FullyQualifiedName abstractFQN) {
-        return """
-            @Override
-            public boolean equals(Object o) {
-                if (this == o) return true;
-                if (o == null || getClass() != o.getClass()) return false;
-                ${abstractFQN.typeName} that = (${abstractFQN.typeName}) o;
-                return identifier.equals(that.identifier);
-            }
-
-            @Override
-            public int hashCode() {
-                return identifier.hashCode();
-            }
-        """
-    }
-
-    private static String getReuseLogic(List<ModuleField> moduleFields, FullyQualifiedName abstractFQN) {
-        String result = """
-            public boolean canReuseInstance(${abstractFQN.typeName} oldModule){
-                // allow reusing of old instance if no parameters was changed
-                return isSame(oldModule);
-            }
-
-            public ${AutoCloseable.canonicalName} reuseInstance(${AutoCloseable.canonicalName} oldInstance){
-                // implement if instance reuse should be supported. Override canReuseInstance to change the criteria.
-                return oldInstance;
-            }
-            """
-        // isSame method that detects changed fields
-        result += """
-            public boolean isSame(${abstractFQN.typeName} other) {
-                if (other == null) {
-                    throw new IllegalArgumentException("Parameter 'other' is null");
-                }
-            """
-        // loop through fields, do deep equals on each field
-        result += moduleFields.collect { field ->
-            if (field.isListOfDependencies()) {
-                return """
-                    if (${field.name}Dependency.equals(other.${field.name}Dependency) == false) {
-                        return false;
-                    }
-                    for (int idx = 0; idx < ${field.name}Dependency.size(); idx++) {
-                        if (${field.name}Dependency.get(idx) != other.${field.name}Dependency.get(idx)) {
-                            return false;
-                        }
-                    }
-                """
-            } else if (field.isDependent()) {
-                return """
-                    if (${field.name}Dependency != other.${field.name}Dependency) { // reference to dependency must be same
-                        return false;
-                    }
-                """
-            } else {
-                return """
-                    if (java.util.Objects.deepEquals(${field.name}, other.${field.name}) == false) {
-                        return false;
-                    }
-                """
-            }
-        }.join("\n")
-
-
-        result += """
-                return true;
-            }
-            """
-
-        return result
-    }
-
-    private static String getGetInstance(List<ModuleField> moduleFields) {
-        String result = """
-            @Override
-            public final ${AutoCloseable.canonicalName} getInstance() {
-                if(instance==null) {
-            """
-        // create instance start
-
-        // loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies.
-        Map<ModuleField, String> resolveDependenciesMap = moduleFields.findAll {
-            it.isDependent()
-        }.collectEntries { ModuleField field ->
-            [field, field.isList() ?
-                    """
-                ${field.name}Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
-                for(javax.management.ObjectName dep : ${field.name}) {
-                    ${field.name}Dependency.add(dependencyResolver.resolveInstance(${
-                        field.dependency.sie.exportedOsgiClassName
-                    }.class, dep, ${field.name}JmxAttribute));
-                }
-                """
-                    :
-                    """
-                ${field.name}Dependency = dependencyResolver.resolveInstance(${
-                        field.dependency.sie.exportedOsgiClassName
-                    }.class, ${field.name}, ${field.name}JmxAttribute);
-                """
-            ]
-        }
-        // wrap each field resolvation statement with if !=null when dependency is not mandatory
-        def wrapWithNullCheckClosure = {Map<ModuleField, String> map, predicate -> map.collect { ModuleField key, String value ->
-            predicate(key) ? """
-                if(${key.name}!=null) {
-                    ${value}
-                }
-                """ : value
-            }.join("\n")
-        }
-
-        result += wrapWithNullCheckClosure(resolveDependenciesMap, {ModuleField key ->
-            key.getDependency().isMandatory() == false} )
-
-        // add code to inject dependency resolver to fields that support it
-        Map<ModuleField, String> injectDepsMap = moduleFields.findAll { it.needsDepResolver }.collectEntries { field ->
-            if (field.isList()) {
-                return [field,"""
-                for(${field.genericInnerType} candidate : ${field.name}) {
-                    candidate.injectDependencyResolver(dependencyResolver);
-                }
-                """]
-            } else {
-                return [field, "${field.name}.injectDependencyResolver(dependencyResolver);"]
-            }
-        }
-
-        result += wrapWithNullCheckClosure(injectDepsMap, {true})
-
-        // identity refs need to be injected with dependencyResolver and base class
-        Map<ModuleField, String> resolveIdentityMap = moduleFields.findAll { it.isIdentityRef() }.collectEntries { IdentityRefModuleField field ->
-            [field,
-            "set${field.attributeName}(${field.name}.resolveIdentity(dependencyResolver, ${field.identityBaseClass}.class));"]
-        }
-
-        result += wrapWithNullCheckClosure(resolveIdentityMap, {true})
-
-        // create instance end: reuse and recreate logic
-        result += """
-                    if(oldInstance!=null && canReuseInstance(oldModule)) {
-                        instance = reuseInstance(oldInstance);
-                    } else {
-                        if(oldInstance!=null) {
-                            try {
-                                oldInstance.close();
-                            } catch(Exception e) {
-                                logger.error("An error occurred while closing old instance " + oldInstance, e);
-                            }
-                        }
-                        instance = createInstance();
-                        if (instance == null) {
-                            throw new IllegalStateException("Error in createInstance - null is not allowed as return value");
-                        }
-                    }
-                }
-                return instance;
-            }
-            public abstract ${AutoCloseable.canonicalName} createInstance();
-            """
-        return result
-    }
-
-    private static String getCommonFields(FullyQualifiedName abstractFQN) {
-        return """
-            private final ${abstractFQN.typeName} oldModule;
-            private final ${AutoCloseable.canonicalName} oldInstance;
-            private ${AutoCloseable.canonicalName} instance;
-            private final ${DependencyResolver.canonicalName} dependencyResolver;
-            private final ${ModuleIdentifier.canonicalName} identifier;
-            @Override
-            public ${ModuleIdentifier.canonicalName} getIdentifier() {
-                return identifier;
-            }
-            """
-    }
-
-    private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
-        return moduleFields.findAll { it.isIdentityRef() }.collect { IdentityRefModuleField field ->
-            "private ${field.identityClassType} ${field.identityClassName};"
-        }.join("\n")
-    }
-
-    private static String getCachesOfResolvedDependencies(List<ModuleField> moduleFields) {
-        return moduleFields.findAll { it.dependent }.collect { field ->
-            if (field.isList()) {
-                return """
-                    private java.util.List<${field.dependency.sie.exportedOsgiClassName}> ${
-                    field.name
-                }Dependency = new java.util.ArrayList<${field.dependency.sie.exportedOsgiClassName}>();
-                    protected final java.util.List<${field.dependency.sie.exportedOsgiClassName}> get${
-                    field.attributeName
-                }Dependency(){
-                        return ${field.name}Dependency;
-                    }
-                    """
-            } else {
-                return """
-                    private ${field.dependency.sie.exportedOsgiClassName} ${field.name}Dependency;
-                    protected final ${field.dependency.sie.exportedOsgiClassName} get${field.attributeName}Dependency(){
-                        return ${field.name}Dependency;
-                    }
-                    """
-            }
-        }.join("\n")
-    }
-
-    private static String getRuntimeRegistratorCode(Optional<FullyQualifiedName> maybeRegistratorType) {
-        if (maybeRegistratorType.isPresent()) {
-            String registratorType = maybeRegistratorType.get()
-
-            return """
-                private ${registratorType} rootRuntimeBeanRegistratorWrapper;
-
-                public ${registratorType} getRootRuntimeBeanRegistratorWrapper(){
-                    return rootRuntimeBeanRegistratorWrapper;
-                }
-
-                @Override
-                public void setRuntimeBeanRegistrator(${RootRuntimeBeanRegistrator.canonicalName} rootRuntimeRegistrator){
-                    this.rootRuntimeBeanRegistratorWrapper = new ${registratorType}(rootRuntimeRegistrator);
-                }
-                """
-        } else {
-            return ""
-        }
-    }
-
-    private static String getValidationMethods(List<ModuleField> moduleFields) {
-        String result = """
-            @Override
-            public void validate() {
-            """
-        // validate each mandatory dependency
-        List<String> lines = moduleFields.findAll{(it.dependent && it.dependency.mandatory)}.collect { field ->
-            if (field.isList()) {
-                return "" +
-                        "for(javax.management.ObjectName dep : ${field.name}) {\n" +
-                        "    dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, dep, ${field.name}JmxAttribute);\n" +
-                        "}\n"
-            } else {
-                return "dependencyResolver.validateDependency(${field.dependency.sie.fullyQualifiedName}.class, ${field.name}, ${field.name}JmxAttribute);"
-            }
-        }
-        result += lines.findAll { it.isEmpty() == false }.join("\n")
-        result += """
-                customValidation();
-            }
-
-            protected void customValidation(){
-            }
-        """
-        return result
-    }
-
-    private static String getLogger(FullyQualifiedName fqn) {
-        return "private static final ${Logger.canonicalName} logger = ${LoggerFactory.canonicalName}.getLogger(${fqn.toString()}.class);"
-    }
-
-    // assumes that each parameter name corresponds to an field in this class, constructs lines setting this.field = field;
-    private static String getConstructorStart(FullyQualifiedName fqn,
-                                              LinkedHashMap<String, String> parameters, String after) {
-        return "public ${fqn.typeName}(" +
-                parameters.collect { it.key + " " + it.value }.join(",") +
-                ") {\n" +
-                parameters.values().collect { "this.${it}=${it};\n" }.join() +
-                after +
-                "}\n"
-    }
-
-    private static String getNewConstructor(FullyQualifiedName abstractFQN) {
-        LinkedHashMap<String, String> parameters = [
-                (ModuleIdentifier.canonicalName): "identifier",
-                (DependencyResolver.canonicalName): "dependencyResolver"
-        ]
-        String setToNulls = ["oldInstance", "oldModule"].collect { "this.${it}=null;\n" }.join()
-        return getConstructorStart(abstractFQN, parameters, setToNulls)
-    }
-
-    private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
-        LinkedHashMap<String, String> parameters = [
-                (ModuleIdentifier.canonicalName): "identifier",
-                (DependencyResolver.canonicalName): "dependencyResolver",
-                (abstractFQN.typeName): "oldModule",
-                (AutoCloseable.canonicalName): "oldInstance"
-        ]
-        return getConstructorStart(abstractFQN, parameters, "")
-    }
-}
diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java
new file mode 100644 (file)
index 0000000..aa06cb9
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory;
+
+import static java.lang.String.format;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.annotations.Description;
+import org.opendaylight.controller.config.api.runtime.RootRuntimeBeanRegistrator;
+import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractModuleTemplate;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.TypeName;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AbsModuleGeneratedObjectFactory {
+
+    public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
+        FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName());
+        Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription());
+        AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe);
+        Optional<String> header = abstractModuleTemplate.getHeaderString();
+
+        List<FullyQualifiedName> implementedInterfaces = new ArrayList<>();
+        for(String implemented: abstractModuleTemplate.getTypeDeclaration().getImplemented()) {
+            implementedInterfaces.add(FullyQualifiedName.fromString(implemented));
+        }
+        Optional<FullyQualifiedName> maybeRegistratorType;
+        if (abstractModuleTemplate.isRuntime()) {
+            maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType()));
+        } else {
+            maybeRegistratorType = Optional.absent();
+        }
+
+        return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces,
+                abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(),
+                mbe.getYangModuleQName());
+    }
+
+    public GeneratedObject toGeneratedObject(FullyQualifiedName abstractFQN,
+                                             Optional<String> copyright,
+                                             Optional<String> header,
+                                             Optional<String> classJavaDoc,
+                                             List<FullyQualifiedName> implementedInterfaces,
+                                             List<ModuleField> moduleFields,
+                                             Optional<FullyQualifiedName> maybeRegistratorType,
+                                             List<? extends Method> methods,
+                                             QName yangModuleQName) {
+        JavaFileInputBuilder b = new JavaFileInputBuilder();
+
+        Annotation moduleQNameAnnotation = Annotation.createModuleQNameANnotation(yangModuleQName);
+        b.addClassAnnotation(moduleQNameAnnotation);
+
+        b.setFqn(abstractFQN);
+        b.setTypeName(TypeName.absClassType);
+
+        b.setCopyright(copyright);
+        b.setHeader(header);
+        b.setClassJavaDoc(classJavaDoc);
+        for(FullyQualifiedName implemented: implementedInterfaces) {
+            b.addImplementsFQN(implemented);
+        }
+        if (classJavaDoc.isPresent()) {
+            b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
+        }
+
+        // add logger:
+        b.addToBody(getLogger(abstractFQN));
+
+        b.addToBody("//attributes start");
+        for(ModuleField moduleField: moduleFields) {
+            b.addToBody(moduleField.toString() +"\n");
+        }
+
+        b.addToBody("//attributes end");
+
+
+        b.addToBody(getCommonFields(abstractFQN));
+
+
+        b.addToBody(getNewConstructor(abstractFQN));
+        b.addToBody(getCopyFromOldConstructor(abstractFQN));
+
+        b.addToBody(getRuntimeRegistratorCode(maybeRegistratorType));
+        b.addToBody(getValidationMethods(moduleFields));
+
+        b.addToBody(getCachesOfResolvedDependencies(moduleFields));
+        b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields));
+        b.addToBody(getGetInstance(moduleFields));
+        b.addToBody(getReuseLogic(moduleFields, abstractFQN));
+        b.addToBody(getEqualsAndHashCode(abstractFQN));
+
+        b.addToBody(getMethods(methods));
+
+        return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
+    }
+
+    private static String getMethods(List<? extends Method>  methods) {
+        String result = "\n// getters and setters\n";
+        for(Method method: methods) {
+            result += method.toString()+"\n";
+        }
+        return result;
+    }
+
+    private static String getEqualsAndHashCode(FullyQualifiedName abstractFQN) {
+        return "\n"+
+            "@Override\n"+
+            "public boolean equals(Object o) {\n"+
+                "if (this == o) return true;\n"+
+                "if (o == null || getClass() != o.getClass()) return false;\n"+
+                format("%s that = (%1$s) o;\n", abstractFQN.getTypeName())+
+                "return identifier.equals(that.identifier);\n"+
+            "}\n"+
+            "\n"+
+            "@Override\n"+
+            "public int hashCode() {\n"+
+                "return identifier.hashCode();\n"+
+            "}\n";
+    }
+
+    private static String getReuseLogic(List<ModuleField> moduleFields, FullyQualifiedName abstractFQN) {
+        String result = "\n"+
+            format("public boolean canReuseInstance(%s oldModule){\n", abstractFQN.getTypeName())+
+                "// allow reusing of old instance if no parameters was changed\n"+
+                "return isSame(oldModule);\n"+
+            "}\n"+
+            "\n"+
+            format("public %s reuseInstance(%1$s oldInstance){\n", AutoCloseable.class.getCanonicalName())+
+                "// implement if instance reuse should be supported. Override canReuseInstance to change the criteria.\n"+
+                "return oldInstance;\n"+
+            "}\n";
+        // isSame method that detects changed fields
+        result += "\n"+
+            format("public boolean isSame(%s other) {\n", abstractFQN.getTypeName())+
+                "if (other == null) {\n"+
+                    "throw new IllegalArgumentException(\"Parameter 'other' is null\");\n"+
+                "}\n";
+        // loop through fields, do deep equals on each field
+
+        for (ModuleField moduleField : moduleFields) {
+            if (moduleField.isListOfDependencies()) {
+                result += format(
+                    "if (%1$sDependency.equals(other.%1$sDependency) == false) {\n"+
+                        "return false;\n"+
+                    "}\n"+
+                    "for (int idx = 0; idx < %1$sDependency.size(); idx++) {\n"+
+                        "if (%1$sDependency.get(idx) != other.%1$sDependency.get(idx)) {\n"+
+                            "return false;\n"+
+                        "}\n"+
+                    "}\n" ,moduleField.getName());
+            } else if (moduleField.isDependent()) {
+                result += format(
+                    "if (%sDependency != other.%1$sDependency) { // reference to dependency must be same\n"+
+                        "return false;\n"+
+                    "}\n",moduleField.getName());
+            } else {
+                result += format(
+                    "if (java.util.Objects.deepEquals(%s, other.%1$s) == false) {\n"+
+                        "return false;\n"+
+                    "}\n", moduleField.getName());
+            }
+        }
+        result += "\n"+
+                "return true;\n"+
+            "}\n";
+
+        return result;
+    }
+
+    private static String getGetInstance(List<ModuleField> moduleFields) {
+        String result = "\n"+
+            "@Override\n"+
+            format("public final %s getInstance() {\n", AutoCloseable.class.getCanonicalName())+
+                "if(instance==null) {\n";
+        // create instance start
+
+        // loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies.
+        Map<ModuleField, String> resolveDependenciesMap = new HashMap<>();
+        for(ModuleField moduleField: moduleFields) {
+            if (moduleField.isDependent()) {
+                String str;
+                String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName();
+                if (moduleField.isList()) {
+                    str = format(
+                        "%sDependency = new java.util.ArrayList<%s>();\n"+
+                        "for(javax.management.ObjectName dep : %1$s) {\n"+
+                            "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
+                        "}\n", moduleField.getName(), osgi);
+                } else {
+                    str = format(
+                        "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);",
+                        moduleField.getName(), osgi);
+                }
+                resolveDependenciesMap.put(moduleField, str);
+            }
+        }
+
+        // wrap each field resolvation statement with if !=null when dependency is not mandatory
+        for (Map.Entry<ModuleField, String> entry : resolveDependenciesMap.entrySet()) {
+            if (entry.getKey().getDependency().isMandatory() == false) {
+                result += format("if (%s!=null) {\n%s;\n}", entry.getKey().getName(), entry.getValue());
+            } else {
+                result += entry.getValue();
+            }
+        }
+
+        // add code to inject dependency resolver to fields that support it
+        for(ModuleField moduleField: moduleFields) {
+            if (moduleField.isNeedsDepResolver()) {
+                result += format("if (%s!=null){\n", moduleField.getName());
+                if (moduleField.isList()) {
+                    result += format(
+                        "for(%s candidate : %s) {\n"+
+                            "candidate.injectDependencyResolver(dependencyResolver);\n"+
+                        "}\n", moduleField.getGenericInnerType(), moduleField.getName());
+                } else {
+                    result += format("%s.injectDependencyResolver(dependencyResolver);\n", moduleField.getName());
+                }
+                result += "}\n";
+            }
+        }
+
+        // identity refs need to be injected with dependencyResolver and base class
+        for (ModuleField moduleField : moduleFields) {
+            if (moduleField.isIdentityRef()) {
+                result += format("if (%s!=null) {", moduleField.getName());
+                result += format("set%s(%s.resolveIdentity(dependencyResolver, %s.class));",
+                        moduleField.getAttributeName(), moduleField.getName(),
+                        ((IdentityRefModuleField)moduleField).getIdentityBaseClass());
+                result += "}\n";
+            }
+        }
+
+        // create instance end: reuse and recreate logic
+        result +=   "if(oldInstance!=null && canReuseInstance(oldModule)) {\n"+
+                        "instance = reuseInstance(oldInstance);\n"+
+                    "} else {\n"+
+                        "if(oldInstance!=null) {\n"+
+                           "try {\n"+
+                                "oldInstance.close();\n"+
+                            "} catch(Exception e) {\n"+
+                                "logger.error(\"An error occurred while closing old instance \" + oldInstance, e);\n"+
+                            "}\n"+
+                        "}\n"+
+                        "instance = createInstance();\n"+
+                        "if (instance == null) {\n"+
+                            "throw new IllegalStateException(\"Error in createInstance - null is not allowed as return value\");\n"+
+                        "}\n"+
+                    "}\n"+
+                "}\n"+
+                "return instance;\n"+
+            "}\n"+
+            format("public abstract %s createInstance();\n", AutoCloseable.class.getCanonicalName());
+
+        return result;
+    }
+
+    private static String getCommonFields(FullyQualifiedName abstractFQN) {
+        return "\n"+
+            format("private final %s oldModule;\n", abstractFQN.getTypeName())+
+            format("private final %s oldInstance;\n", AutoCloseable.class.getCanonicalName())+
+            format("private %s instance;\n", AutoCloseable.class.getCanonicalName())+
+            format("private final %s dependencyResolver;\n", DependencyResolver.class.getCanonicalName())+
+            format("private final %s identifier;\n", ModuleIdentifier.class.getCanonicalName())+
+            "@Override\n"+
+            format("public %s getIdentifier() {\n", ModuleIdentifier.class.getCanonicalName())+
+                "return identifier;\n"+
+            "}\n";
+    }
+
+    private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
+        StringBuilder result = new StringBuilder();
+        for (ModuleField moduleField : moduleFields) {
+            if (moduleField.isIdentityRef()) {
+                IdentityRefModuleField field = (IdentityRefModuleField) moduleField;
+                result.append(format("private %s %s;\n", field.getIdentityClassType(), field.getIdentityClassName()));
+            }
+        }
+        return result.toString();
+    }
+
+    private static String getCachesOfResolvedDependencies(List<ModuleField> moduleFields) {
+        StringBuilder result = new StringBuilder();
+        for (ModuleField moduleField: moduleFields) {
+            if (moduleField.isDependent()) {
+                String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName();
+                if (moduleField.isList()) {
+                    result
+                            .append(format("private java.util.List<%s> %sDependency = new java.util.ArrayList<%s>();", osgi, moduleField.getName(), osgi))
+                            .append(format("protected final java.util.List<%s> get%sDependency(){\n", osgi, moduleField.getAttributeName()))
+                            .append(format("return %sDependency;\n", moduleField.getName()))
+                            .append("}\n");
+                } else {
+                    result.append(format(
+                    "private %s %sDependency;\n"+
+                    "protected final %s get%sDependency(){\n"+
+                        "return %sDependency;\n"+
+                    "}",
+                    osgi, moduleField.getName(), osgi, moduleField.getAttributeName(), moduleField.getName()));
+                }
+            }
+        }
+        return result.toString();
+    }
+
+    private static String getRuntimeRegistratorCode(Optional<FullyQualifiedName> maybeRegistratorType) {
+        if (maybeRegistratorType.isPresent()) {
+            String registratorType = maybeRegistratorType.get().toString();
+
+            return "\n"+
+                format("private %s rootRuntimeBeanRegistratorWrapper;\n", registratorType)+
+                "\n"+
+                format("public %s getRootRuntimeBeanRegistratorWrapper(){\n", registratorType)+
+                    "return rootRuntimeBeanRegistratorWrapper;\n"+
+                "}\n"+
+                "\n"+
+                "@Override\n"+
+                format("public void setRuntimeBeanRegistrator(%s rootRuntimeRegistrator){\n", RootRuntimeBeanRegistrator.class.getCanonicalName())+
+                    format("this.rootRuntimeBeanRegistratorWrapper = new %s(rootRuntimeRegistrator);\n", registratorType)+
+                "}\n";
+        } else {
+            return "";
+        }
+    }
+
+    private static String getValidationMethods(List<ModuleField> moduleFields) {
+        String result = "\n"+
+            "@Override\n"+
+            "public void validate() {\n";
+        // validate each mandatory dependency
+        for(ModuleField moduleField: moduleFields) {
+            if (moduleField.isDependent() && moduleField.getDependency().isMandatory()) {
+                if (moduleField.isList()) {
+                    result += "" +
+                            format("for(javax.management.ObjectName dep : %s) {\n", moduleField.getName()) +
+                            format("    dependencyResolver.validateDependency(%s.class, dep, %sJmxAttribute);\n",
+                                    moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName()) +
+                            "}\n";
+                } else {
+                    result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);",
+                            moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName(), moduleField.getName());
+                }
+            }
+        }
+        result += "\n"+
+                "customValidation();\n"+
+            "}\n"+
+            "\n"+
+            "protected void customValidation() {\n"+
+            "}\n";
+        return result;
+    }
+
+    private static String getLogger(FullyQualifiedName fqn) {
+        return format("private static final %s logger = %s.getLogger(%s.class);",
+                Logger.class.getCanonicalName(), LoggerFactory.class.getCanonicalName(), fqn);
+    }
+
+    // assumes that each parameter name corresponds to an field in this class, constructs lines setting this.field = field;
+    private static String getConstructorStart(FullyQualifiedName fqn,
+                                              LinkedHashMap<String, String> parameters, String after) {
+        String paramString = Joiner.on(",").withKeyValueSeparator(" ").join(parameters);
+        String setters = "";
+        for (String paramName : parameters.values()) {
+            setters += format("this.%s = %1$s;\n", paramName);
+        }
+        return format("public %s(", fqn.getTypeName()) +
+                paramString +
+                ") {\n" +
+                setters +
+                after +
+                "}\n";
+    }
+
+    private static String getNewConstructor(FullyQualifiedName abstractFQN) {
+        LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
+        parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier");
+        parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
+
+        String setToNulls = "this.oldInstance=null;\n;" +
+                "this.oldModule=null;\n";
+        return getConstructorStart(abstractFQN, parameters, setToNulls);
+    }
+
+    private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
+        LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
+        parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier");
+        parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
+        parameters.put(abstractFQN.getTypeName(), "oldModule");
+        parameters.put(AutoCloseable.class.getCanonicalName(), "oldInstance");
+        return getConstructorStart(abstractFQN, parameters, "");
+    }
+}
diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/GenericGeneratedObjectFactory.groovy b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/GenericGeneratedObjectFactory.groovy
deleted file mode 100644 (file)
index 6504aac..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory
-
-import com.google.common.base.Optional
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.FtlTemplate
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder
-
-public class GenericGeneratedObjectFactory {
-
-    public GeneratedObject toGeneratedObject(FtlTemplate template, Optional<String> copyright) {
-        JavaFileInputBuilder b = new JavaFileInputBuilder();
-        b.setHeader(template.headerString)
-        b.setFqn(new FullyQualifiedName(template.packageName, template.typeDeclaration.name))
-        b.setClassJavaDoc(template.maybeJavadoc)
-        template.annotations.each { b.addClassAnnotation(it) }
-        // type declaration
-        template.typeDeclaration.extended.each { b.addExtendsFQN(FullyQualifiedName.fromString(it)) }
-        template.typeDeclaration.implemented.each { b.addImplementsFQN(FullyQualifiedName.fromString(it)) }
-        b.setCopyright(copyright);
-        b.setTypeName(template.typeDeclaration.toTypeName())
-        // fields
-        template.fields.each { b.addToBody(it.toString()) }
-        // constructors
-        template.constructors.each { b.addToBody(it.toString()) }
-        // methods
-        template.methods.each { b.addToBody(it.toString()) }
-
-        return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
-    }
-}
diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/GenericGeneratedObjectFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/GenericGeneratedObjectFactory.java
new file mode 100644 (file)
index 0000000..11bb677
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yangjmxgenerator.plugin.gofactory;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.FtlTemplate;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObjectBuilder;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder;
+
+public class GenericGeneratedObjectFactory {
+
+    public GeneratedObject toGeneratedObject(FtlTemplate template, Optional<String> copyright) {
+        JavaFileInputBuilder b = new JavaFileInputBuilder();
+        b.setHeader(template.getHeaderString());
+        b.setFqn(new FullyQualifiedName(template.getPackageName(), template.getTypeDeclaration().getName()));
+        b.setClassJavaDoc(template.getMaybeJavadoc());
+        for (Annotation annotation : template.getAnnotations()) {
+            b.addClassAnnotation(annotation);
+        }
+        // type declaration
+        for (String extended : template.getTypeDeclaration().getExtended()) {
+            b.addExtendsFQN(FullyQualifiedName.fromString(extended));
+        }
+        for (String implemented : template.getTypeDeclaration().getImplemented()) {
+            b.addImplementsFQN(FullyQualifiedName.fromString(implemented));
+        }
+        b.setCopyright(copyright);
+        b.setTypeName(template.getTypeDeclaration().toTypeName());
+        // fields
+        for (Field field : template.getFields()) {
+            b.addToBody(field.toString());
+        }
+        // constructors
+        for (Constructor constructor : template.getConstructors()) {
+            b.addToBody(constructor.toString());
+        }
+        // methods
+        for (Method method : template.getMethods()) {
+            b.addToBody(method.toString());
+        }
+        return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
+    }
+}
index f2a56f2b1bfbe2a1e1066a90f3ef16ba6afef660..7a20f22440a75dc97f45ed9575c1d9364f40c3fb 100644 (file)
@@ -44,22 +44,53 @@ public class ProcessSources extends AbstractMojo{
 
         File[] sourceFiles = sourceDirectory.listFiles();
         for (File sourceFile: sourceFiles) {
-            if(sourceFile.getName().endsWith("Module.java") || sourceFile.getName().endsWith("ModuleFactory.java")) {
-                File stubFile = new File(sourceFile.getPath().replace(".java", "Stub.txt"));
-                if (stubFile.exists()) {
-                    try {
-                        rewrite(sourceFile, FileUtils.readFileToString(stubFile));
-                    } catch (IOException e) {
-                        getLog().error("Error while reading/writing to files.", e);
+            if (sourceFile.getName().endsWith(".java")) {
+                String sourceContent;
+                try {
+                    sourceContent = FileUtils.readFileToString(sourceFile);
+                } catch (IOException e) {
+                    getLog().error("Cannot read " + sourceFile.getAbsolutePath(), e);
+                    continue;
+                }
+                if (sourceFile.getName().endsWith("Module.java") || sourceFile.getName().endsWith("ModuleFactory.java")) {
+                    File stubFile = new File(sourceFile.getPath().replace(".java", "Stub.txt"));
+                    if (stubFile.exists()) {
+                        String stubContent = null;
+                        try {
+                            stubContent = FileUtils.readFileToString(stubFile);
+                        } catch (IOException e) {
+                            getLog().error("Cannot read " + stubFile.getAbsolutePath(), e);
+                        }
+                        if (stubContent != null) {
+                            sourceContent = rewriteStub(sourceContent, stubContent);
+                        }
                     }
                 }
+                // remove copyright headers as they can contain timestamp
+                sourceContent = removeCopyrights(sourceContent);
+
+                // replace the file content
+                try {
+                    FileUtils.write(sourceFile, sourceContent);
+                } catch (IOException e) {
+                    getLog().error("Cannot write " + sourceFile.getAbsolutePath(), e);
+                }
             }
+
         }
     }
 
-    private static void rewrite(File sourceFile, String replaceTODOWith) throws IOException {
-        String source = FileUtils.readFileToString(sourceFile);
-        String target = Pattern.compile("^.*TODO.*\n.*throw new java.lang.UnsupportedOperationException.*$", Pattern.MULTILINE).matcher(source).replaceFirst(replaceTODOWith);
-        FileUtils.write(sourceFile, target);
+    private static Pattern MULTILINE_COMMENT_PATTERN = Pattern.compile("/\\*.*\\*/", Pattern.MULTILINE | Pattern.DOTALL);
+    private static String removeCopyrights(String source) {
+        String target = MULTILINE_COMMENT_PATTERN.matcher(source).replaceAll("\n");
+        //FileUtils.write(sourceFile, target);
+        return target;
+    }
+
+    private static Pattern UNSUPPORTED_OP_PATTERN = Pattern.compile("^.*TODO.*\n.*throw new java.lang.UnsupportedOperationException.*$", Pattern.MULTILINE);
+
+    private static String rewriteStub(String source, String replaceTODOWith) {
+        String target = UNSUPPORTED_OP_PATTERN.matcher(source).replaceFirst(replaceTODOWith);
+        return target;
     }
 }
index 07d7438a00b9758ccd28ee10b70f2059b37f77a8..78ac362e594e393b2a9128cce895d3e4d2c9f4e7 100644 (file)
@@ -1,10 +1,5 @@
-/*
-* Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Eclipse Public License v1.0 which accompanies this distribution,
-* and is available at http://www.eclipse.org/legal/epl-v10.html
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class DepTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModule {
     public DepTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
index ae6ae675840dcd52c9379da9e502d4528a3cac52..026dd9aca28b873c2268d0f269dab5702dca1bba 100644 (file)
@@ -1,19 +1,5 @@
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl-dep
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class DepTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractDepTestImplModuleFactory {
 
index a5b7f55df382b4b403404f168a32bfd04c8a1976..ddf72f39b4da73d529ddac371b9fc64cd9158a0f 100644 (file)
@@ -1,10 +1,5 @@
-/*
-* Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Eclipse Public License v1.0 which accompanies this distribution,
-* and is available at http://www.eclipse.org/legal/epl-v10.html
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class IdentityTestModule extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModule {
     public IdentityTestModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
index 07012263e17b8a34232d83c34e8813873cd07c11..3a4348d376f8841d1dbc3c9f17ef391214588f82 100644 (file)
@@ -1,19 +1,5 @@
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl-identity-test
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class IdentityTestModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractIdentityTestModuleFactory {
 
index ecbf4aba33c436b9354f4c4abe0a674de258745c..943fe3b0d7709cc979a84c54ed6c7df8c24d3fc8 100644 (file)
@@ -1,10 +1,5 @@
-/*
-* Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Eclipse Public License v1.0 which accompanies this distribution,
-* and is available at http://www.eclipse.org/legal/epl-v10.html
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class NetconfTestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModule {
     public NetconfTestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
index 3baee6c132129d576b6df7958314dda14176ade8..587089b10f488d9f9c03090469cb00f6d9b0a865 100644 (file)
@@ -1,19 +1,5 @@
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl-netconf
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class NetconfTestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractNetconfTestImplModuleFactory {
 
index 4de980433753e4165f66dec8fe2eb7081073ddd5..1d5cda036f8a05867b94d04e947c0c0ddec4a88f 100644 (file)
@@ -1,10 +1,5 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 
 import com.google.common.collect.Lists;
index 9132407356e8b4c52ab23610079d1d189e029c8b..7b049e7b578e9ae8d94bd85a7e4a18a842a520ca 100644 (file)
@@ -1,10 +1,5 @@
-/*
-* Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
-*
-* This program and the accompanying materials are made available under the
-* terms of the Eclipse Public License v1.0 which accompanies this distribution,
-* and is available at http://www.eclipse.org/legal/epl-v10.html
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class TestImplModule extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModule {
     public TestImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
index 6f9118bf921d134547079a38f73cd55592e342de..de9ac2fef3ad363e8952384b526be688ab5b6dbc 100644 (file)
@@ -1,19 +1,5 @@
-/*
-* 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
-*/
-/*
-* Generated file
-*
-* Generated from: yang module name: config-test-impl yang module local name: impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Apr 25 11:50:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
+
+
 package org.opendaylight.controller.config.yang.test.impl;
 public class TestImplModuleFactory extends org.opendaylight.controller.config.yang.test.impl.AbstractTestImplModuleFactory {
 
diff --git a/opendaylight/distribution/opendaylight-karaf/pom.xml b/opendaylight/distribution/opendaylight-karaf/pom.xml
new file mode 100644 (file)
index 0000000..60f660a
--- /dev/null
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.2-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+  <artifactId>distribution.opendaylight-karaf</artifactId>
+  <packaging>pom</packaging>
+  <prerequisites>
+    <maven>3.0</maven>
+  </prerequisites>
+
+  <dependencies>
+    <dependency>
+      <!-- scope is compile so all features (there is only one) are installed
+            into startup.properties and the feature repo itself is not installed -->
+      <groupId>org.apache.karaf.features</groupId>
+      <artifactId>framework</artifactId>
+      <version>${karaf.version}</version>
+      <type>kar</type>
+    </dependency>
+    <!-- scope is runtime so the feature repo is listed in the features
+      service config file, and features may be installed using the
+      karaf-maven-plugin configuration -->
+    <!-- dependencies commented out till we can get them in
+    <dependency>
+      <groupId>org.apache.karaf.features</groupId>
+      <artifactId>standard</artifactId>
+      <version>${karaf.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>controller-features</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-file</artifactId>
+      <version>${yangtools.version}</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>
+          <!-- no startupFeatures -->
+          <bootFeatures>
+            <feature>standard</feature>
+          </bootFeatures>
+          <!-- no installedFeatures -->
+        </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-checkstyle-plugin</artifactId>
+        <version>${checkstyle.version}</version>
+        <configuration>
+          <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/configuration\/initial\/</excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+  </scm>
+</project>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/context.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/context.xml
new file mode 100644 (file)
index 0000000..90b9ddf
--- /dev/null
@@ -0,0 +1 @@
+<Context crossContext="true" sessionCookiePath="/" useHttpOnly="false"/>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/00-netty.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/00-netty.xml
new file mode 100644 (file)
index 0000000..2365c70
--- /dev/null
@@ -0,0 +1,60 @@
+<snapshot>
+    <required-capabilities>
+        <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">
+                <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">
+                <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/distribution/opendaylight-karaf/src/main/resources/configuration/initial/01-md-sal.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/01-md-sal.xml
new file mode 100644 (file)
index 0000000..619ab06
--- /dev/null
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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>
+    <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:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+                    <name>yang-schema-service</name>
+                </module>
+                <!-- To enable use of new in-memory datastore and new implementations
+                     of data brokers, comment out all parts of this
+                     xml which are marked with DATA-BROKER and uncomment all parts
+                     of this xml which are marked with NEW-DATA-BROKER
+                -->
+                <!-- DATA-BROKER start-->
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+                    <name>hash-map-data-store</name>
+                </module>
+                <!-- DATA BROKER end -->
+                <!-- NEW-DATA-BROKER start -->
+                <!--
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
+                    <name>async-data-broker</name>
+                    <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>
+                -->
+                <!-- NEW-DATA-BROKER end -->
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+                    <name>dom-broker</name>
+                    <!-- DATA-BROKER start -->
+                    <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+                        <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
+                        <name>hash-map-data-store</name>
+                        <!-- <name>cluster-data-store</name> -->
+                    </data-store>
+                    <!-- DATA-BROKER end -->
+                    <!-- NEW-DATA-BROKER start -->
+                    <!--
+                    <async-data-broker>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+                        <name>async-data-broker</name>
+                    </async-data-broker>
+                    -->
+                    <!-- NEW-DATA-BROKER end -->
+                </module>
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+                    <name>binding-broker-impl</name>
+                    <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+                        <name>binding-notification-broker</name>
+                    </notification-service>
+                    <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                        <name>binding-data-broker</name>
+                    </data-broker>
+                </module>
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+                    <name>runtime-mapping-singleton</name>
+                </module>
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+                    <name>binding-notification-broker</name>
+                </module>
+                <!-- DATA-BROKER start -->
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+                    <name>binding-data-broker</name>
+                    <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                        <name>dom-broker</name>
+                    </dom-broker>
+                    <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+                        <name>runtime-mapping-singleton</name>
+                    </mapping-service>
+                </module>
+                <!-- DATA-BROKER end -->
+                <!-- NEW-DATA-BROKER start -->
+                <!--
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
+                    <name>binding-data-broker</name>
+                    <dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                        <name>dom-broker</name>
+                    </dom-async-broker>
+                    <binding-mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+                        <name>runtime-mapping-singleton</name>
+                    </binding-mapping-service>
+                </module>
+                -->
+                <!-- NEW-DATA-BROKER end -->
+            </modules>
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+                    <instance>
+                        <name>yang-schema-service</name>
+                        <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
+                    </instance>
+                </service>
+                <service>
+                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+                    <instance>
+                        <name>binding-notification-broker</name>
+                        <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+                    </instance>
+                </service>
+                <!-- DATA-BROKER start -->
+                <service>
+                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
+                    <instance>
+                        <name>hash-map-data-store</name>
+                        <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
+                    </instance>
+                </service>
+                <!-- DATA-BROKER end -->
+                <!-- NEW-DATA-BROKER start -->
+                <!--
+                <service>
+                    <type  xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+                    <instance>
+                        <name>async-data-broker</name>
+                        <provider>/modules/module[type='dom-inmemory-data-broker'][name='async-data-broker']</provider>
+                    </instance>
+                </service>
+                -->
+                <!-- NEW-DATA-BROKER end -->
+                <service>
+                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+                    <instance>
+                        <name>binding-osgi-broker</name>
+                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                    </instance>
+                </service>
+                <service>
+                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                    <instance>
+                        <name>binding-rpc-broker</name>
+                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                    </instance>
+                </service>
+                <service>
+                    <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+                    <instance>
+                        <name>runtime-mapping-singleton</name>
+                        <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
+                    </instance>
+                </service>
+                <service>
+                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                    <instance>
+                        <name>dom-broker</name>
+                        <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
+                    </instance>
+                </service>
+
+                <service>
+                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                    <instance>
+                        <name>binding-data-broker</name>
+                        <!--  DATA-BROKER start -->
+                        <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
+                        <!--  DATA-BROKER end -->
+                        <!-- NEW-DATA-BROKER start -->
+                        <!--
+                        <provider>/modules/module[type='binding-data-compatible-broker'][name='binding-data-broker']</provider>
+                        -->
+                        <!--  NEW-DATA-BROKER end -->
+                    </instance>
+                </service>
+
+            </services>
+        </data>
+    </configuration>
+    <required-capabilities>
+        <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:threadpool?module=threadpool&amp;revision=2013-04-09</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&amp;revision=2013-10-28</capability>
+    </required-capabilities>
+</snapshot>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/02-clustering.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/02-clustering.xml
new file mode 100644 (file)
index 0000000..7853b86
--- /dev/null
@@ -0,0 +1,27 @@
+<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:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">prefix:remote-zeromq-rpc-server</type>
+                   <name>remoter</name>
+                   <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">5666</port>
+                   <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc">
+                       <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+                       <name>dom-broker</name>
+                   </dom-broker>
+               </module>
+            </modules>
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+            </services>
+        </data>
+    </configuration>
+
+    <required-capabilities>
+       <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote:rpc?module=odl-sal-dom-rpc-remote-cfg&amp;revision=2013-10-28</capability>
+    </required-capabilities>
+</snapshot>
+
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/03-toaster-sample.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/03-toaster-sample.xml
new file mode 100644 (file)
index 0000000..c481485
--- /dev/null
@@ -0,0 +1,73 @@
+<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:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
+                        prefix:toaster-provider-impl
+                    </type>
+                    <name>toaster-provider-impl</name>
+
+                    <rpc-registry>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                        <name>binding-rpc-broker</name>
+                    </rpc-registry>
+
+                    <notification-service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                            binding:binding-notification-service
+                        </type>
+                        <name>binding-notification-broker</name>
+                    </notification-service>
+                </module>
+
+                <module>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
+                        prefix:toaster-consumer-impl
+                    </type>
+                    <name>toaster-consumer-impl</name>
+
+                    <rpc-registry>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                        <name>binding-rpc-broker</name>
+                    </rpc-registry>
+
+                    <notification-service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                            binding:binding-notification-service
+                        </type>
+                        <name>binding-notification-broker</name>
+                    </notification-service>
+                </module>
+            </modules>
+
+            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <service>
+                    <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider">toaster:toaster-provider</type>
+                    <instance>
+                        <name>toaster-provider</name>
+                        <provider>/modules/module[type='toaster-provider-impl'][name='toaster-provider-impl']</provider>
+                    </instance>
+                </service>
+                <service>
+                    <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer">toaster:toaster-consumer</type>
+                    <instance>
+                        <name>toaster-consumer</name>
+                        <provider>/modules/module[type='toaster-consumer-impl'][name='toaster-consumer-impl']</provider>
+                    </instance>
+                </service>
+            </services>
+        </data>
+
+    </configuration>
+
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&amp;revision=2014-01-31</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&amp;revision=2014-01-31</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&amp;revision=2014-01-31</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&amp;revision=2014-01-31</capability>
+    </required-capabilities>
+
+</snapshot>
+
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/logback.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/logback.xml
new file mode 100644 (file)
index 0000000..d1a5dcc
--- /dev/null
@@ -0,0 +1,97 @@
+ <configuration scan="true">
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+  <appender name="opendaylight.log" class="ch.qos.logback.core.rolling.RollingFileAppender">
+    <file>logs/opendaylight.log</file>
+
+    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+      <fileNamePattern>logs/opendaylight.%d.log.zip</fileNamePattern>
+      <maxHistory>1</maxHistory>
+    </rollingPolicy>
+
+    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+      <maxFileSize>10MB</maxFileSize>
+    </triggeringPolicy>
+
+    <encoder>
+      <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{35} - %msg%n</pattern>
+    </encoder>
+  </appender>
+  <appender name="audit-file" class="ch.qos.logback.core.FileAppender">
+        <file>logs/audit.log</file>
+        <append>true</append>
+        <encoder>
+            <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} %msg %n</pattern>
+        </encoder>
+  </appender>
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+    <appender-ref ref="opendaylight.log" />
+  </root>
+
+  <!--  Base log level  -->
+  <logger name="org.opendaylight" level="INFO"/>
+
+
+  <!-- Controller log level -->
+  <logger name="org.opendaylight.controller" level="INFO"/>
+
+  <!-- OSGi logging bridge -->
+  <logger name="org.opendaylight.controller.logging.bridge" level="WARN"/>
+  <logger name="org.opendaylight.controller.logging.bridge.internal" level="WARN"/>
+
+  <!-- Netty -->
+  <logger name="io.netty" level="WARN"/>
+
+  <!-- Openflow Protocol Plugin -->
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.DiscoveryService" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.InventoryService" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.InventoryServiceShim" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.TopologyServices" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.internal.TopologyServiceShim" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.Controller" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.SwitchHandler" level="INFO"/>
+  <logger name="org.opendaylight.controller.protocol_plugin.openflow.core.internal.SwitchIOSecureService" level="INFO"/>
+  <!-- SAL  -->
+  <logger name="org.opendaylight.controller.sal" level="INFO"/>
+  <logger name="org.opendaylight.controller.sal.implementation" level="INFO"/>
+  <logger name="org.opendaylight.controller.sal.implementation.internal.Inventory" level="INFO"/>
+  <logger name="org.opendaylight.controller.sal.implementation.internal.Topology" level="INFO"/>
+     <!-- remoterpc router and remoterpc routing table -->
+  <logger name="org.opendaylight.controller.sal.connector.remoterpc" level="INFO" />
+  <!-- Functional Modules -->
+  <logger name="org.opendaylight.controller.arphandler" level="INFO"/>
+  <logger name="org.opendaylight.controller.hosttracker" level="INFO"/>
+  <logger name="org.opendaylight.controller.routing" level="INFO"/>
+  <logger name="org.opendaylight.controller.forwardingrulesmanager" level="INFO"/>
+  <logger name="org.opendaylight.controller.forwarding.ipswitch" level="INFO"/>
+  <logger name="org.opendaylight.controller.switchmanager" level="INFO"/>
+  <logger name="org.opendaylight.controller.topologymanager" level="INFO"/>
+  <logger name="org.opendaylight.controller.usermanager" level="INFO"/>
+  <!-- Web modules -->
+  <logger name="org.opendaylight.controller.web" level="INFO"/>
+
+  <!--
+       Unsynchronized controller startup causes models to crop up in random
+       order, which results in temporary inability to fully resolve a model,
+       which is usually resolved. Do not flood console, but keep the messages,
+       as they may be indicating and error.
+  -->
+  <logger name="org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort" level="INFO" additivity="false">
+    <appender-ref ref="opendaylight.log"/>
+  </logger>
+
+  <!-- To debug MD-SAL schema loading issues, uncomment this -->
+  <!--logger name="org.opendaylight.yangtools.yang.parser.impl.util.URLSchemaContextResolver" level="DEBUG"/>
+  <logger name="org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl" level="TRACE"/-->
+
+  <!-- additivity=false ensures analytics data only goes to the analytics log -->
+  <logger name="audit" level="INFO" additivity="false">
+       <appender-ref ref="audit-file"/>
+  </logger>
+</configuration>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/tomcat-logging.properties b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/tomcat-logging.properties
new file mode 100644 (file)
index 0000000..3dbd992
--- /dev/null
@@ -0,0 +1,42 @@
+############################################################
+# Configuration file for tomcat logging
+############################################################
+# Handlers:
+# "handlers" specifies a comma separated list of log Handler
+# classes.  These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# Following line configures a ConsoleHandler and a FileHandler
+
+handlers= java.util.logging.FileHandler,java.util.logging.ConsoleHandler
+
+############################################################
+# Handler specific properties
+# Describes specific configuration info for Handlers
+# JUL does not support rolling file handler based on date
+# For now we will keep count of files to 5 with rolling size of 10MB
+############################################################
+
+java.util.logging.FileHandler.pattern = logs/tomcat%g.log
+java.util.logging.FileHandler.limit = 104857600
+java.util.logging.FileHandler.count = 5
+java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
+java.util.logging.FileHandler.append = true
+java.util.logging.FileHandler.level = INFO
+
+# Limit the message that are printed on the console to SEVERE and above.
+java.util.logging.ConsoleHandler.level = WARNING
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+# SimpleFormatter output format to print one-line log message like this:
+# <YYYY>-<MM>-<DD> <HH>:<MM>:<SS> <TimeZone> [<SOURCE>] ><LOG_LEVEL> <LOGGER> <MESSAGE> <THROWABLE>
+#
+java.util.logging.SimpleFormatter.format=%1$tF %1$tT %1$tZ [%3$s] %4$s %2$s %5$s%6$s%n
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages
+#org.apache.catalina = SEVERE
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/tomcat-server.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/tomcat-server.xml
new file mode 100644 (file)
index 0000000..f6f923e
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<Server>
+  <!--APR library loader. Documentation at /docs/apr.html -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
+  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
+  <Listener className="org.apache.catalina.core.JasperListener" />
+  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
+  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
+
+  <Service name="Catalina">
+    <Connector port="8080" protocol="HTTP/1.1"
+               connectionTimeout="20000"
+               redirectPort="8443" />
+
+<!--
+        Please remove the comments around the following Connector tag to enable HTTPS Authentication support.
+        Remember to add a valid keystore in the configuration folder.
+        More info : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+-->
+
+ <!--
+    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
+               maxThreads="150" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS"
+               keystoreFile="configuration/keystore"
+               keystorePass="changeit"/>
+ -->
+
+    <Engine name="Catalina" defaultHost="localhost">
+      <Host name="localhost" appBase=""
+            unpackWARs="false" autoDeploy="false"
+            deployOnStartup="false" createDirs="false">
+<!--         <Realm className="org.opendaylight.controller.security.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"
+                        rotatable="true" fileDateFormat="yyyy-MM"
+                        pattern="%{yyyy-MM-dd HH:mm:ss.SSS z}t - [%a] - %r"/>
+      </Host>
+    </Engine>
+  </Service>
+</Server>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/custom.properties b/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/custom.properties
new file mode 100644 (file)
index 0000000..9a86866
--- /dev/null
@@ -0,0 +1,114 @@
+# Extra packages to import from the boot class loader
+org.osgi.framework.system.packages.extra=sun.reflect,sun.reflect.misc,sun.misc,sun.nio.ch
+
+# 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:
+osgi.hook.configurators.include=org.eclipse.virgo.kernel.equinox.extensions.hooks.ExtensionsHookConfigurator
+
+# Embedded Tomcat configuration File
+org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
+org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
+
+# Use Equinox as default OSGi Framework Implementation
+karaf.framework=equinox
+
+# Netconf startup configuration
+netconf.tcp.address=127.0.0.1
+netconf.tcp.port=8383
+
+netconf.tcp.client.address=127.0.0.1
+netconf.tcp.client.port=8383
+
+netconf.ssh.address=0.0.0.0
+netconf.ssh.port=1830
+netconf.ssh.pk.path = ./configuration/RSA.pk
+
+
+netconf.config.persister.active=1,2
+# read startup configuration
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
+netconf.config.persister.1.properties.directoryStorage=configuration/initial/
+
+# include only xml files, files with other extensions will be skipped, multiple extensions are permitted e.g. netconf.config.persister.1.properties.includeExtensions=xml,cfg,config
+netconf.config.persister.1.properties.includeExtensions=xml
+netconf.config.persister.1.readonly=true
+
+netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
+netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml
+netconf.config.persister.2.properties.numberOfBackups=1
+
+# logback configuration
+logback.configurationFile=configuration/logback.xml
+
+# Container configuration
+container.profile = Container
+
+# Connection manager configuration
+connection.scheme = ANY_CONTROLLER_ONE_MASTER
+
+# Open Flow related system parameters
+# TCP port on which the controller is listening (default 6633)
+# of.listenPort=6633
+# IP address of the controller (default: wild card)
+# of.address = 127.0.0.1
+# The time (in milliseconds) the controller will wait for a response after sending a Barrier Request or a Statistic Request message (default 2000 msec)
+# of.messageResponseTimer=2000
+# The switch liveness timeout value (default 60500 msec)
+# of.switchLivenessTimeout=60500
+# The size of the queue holding pending statistics requests (default 64). For large networks of n switches, it is recommended to set the queue size to n
+# of.statsQueueSize = 64
+# The flow statistics polling interval in second (default 10 sec)
+# of.flowStatsPollInterval=10
+# The port statistics polling interval in second (default 5 sec)
+# of.portStatsPollInterval=5
+# The description statistics polling interval in second (default 60 sec)
+# of.descStatsPollInterval=60
+# The table statistics polling interval in second (default 10 sec)
+# of.tableStatsPollInterval=10
+# The maximum number of asynchronous messages can be sent before sending a Barrier Request (default 100)
+# of.barrierMessagePriorCount=100
+# The interval which determines how often the discovery packets should be sent (default 300 sec)
+# of.discoveryInterval=300
+# The timeout multiple of discovery interval
+# of.discoveryTimeoutMultiple=2
+# For newly added ports, allow one more retry if the elapsed time exceeds this threshold (default 30 sec)
+# of.discoveryThreshold=30
+# The maximum number of ports handled in one discovery batch (default 512)
+# of.discoveryBatchMaxPorts=512
+
+# OVSDB configuration
+# ovsdb plugin supports both active and passive connections. It listens on port 6640 by default for Active connections.
+ovsdb.listenPort=6640
+
+# ovsdb creates Openflow nodes/bridges. This configuration configures the bridge's Openflow version.
+# default Openflow version = 1.0, we also support 1.3.
+# ovsdb.of.version=1.3
+
+# TLS configuration
+# To enable TLS, set secureChannelEnabled=true and specify the location of controller Java KeyStore and TrustStore files.
+# The Java KeyStore contains controller's private key and certificate. The Java TrustStore contains the trusted certificate
+# entries, including switches' Certification Authority (CA) certificates. For example,
+# secureChannelEnabled=true
+# controllerKeyStore=./configuration/ctlKeyStore
+# controllerKeyStorePassword=xxxxxxxx (this password should match the password used for KeyStore generation and at least 6 characters)
+# controllerTrustStore=./configuration/ctlTrustStore
+# controllerTrustStorePassword=xxxxxxxx (this password should match the password used for TrustStore generation and at least 6 characters)
+
+secureChannelEnabled=false
+controllerKeyStore=
+controllerKeyStorePassword=
+controllerTrustStore=
+controllerTrustStorePassword=
+
+# User Manager configurations
+enableStrongPasswordCheck = false
+
+#Jolokia configurations
+org.jolokia.listenForHttpService=false
+
+# Logging configuration for Tomcat-JUL logging
+java.util.logging.config.file=configuration/tomcat-logging.properties
+
+#Hosttracker hostsdb key scheme setting
+hosttracker.keyscheme=IP
\ No newline at end of file
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/version.properties b/opendaylight/distribution/opendaylight-karaf/src/main/resources/version.properties
new file mode 100644 (file)
index 0000000..90af49d
--- /dev/null
@@ -0,0 +1,6 @@
+org.opendaylight.controller.version = 0.1
+org.opendaylight.controller.build.scm.version = ${buildNumber}
+org.opendaylight.controller.build.user = ${env.USER}
+org.opendaylight.controller.build.workspace = **********
+org.opendaylight.controller.build.timestamp = ${timestamp}
+org.opendaylight.controller.build.machine = **********
index 4eb764fa39e1040b6a2b0e3c44381240f4ef568e..615668f5ebd766c07705161698826a2c4c3f6c90 100644 (file)
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>netconf-client</artifactId>
         </dependency>
+
+        <!--Netconf config-->
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>netconf-config-dispatcher</artifactId>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>netconf-impl</artifactId>
index 9d0d6c1888a480aa96042fc2c7824aaf41b5ecbf..234e0feb45047ed2ca14e45e2b2e1dd18432834e 100644 (file)
@@ -22,6 +22,8 @@ netconf.tcp.client.port=8383
 netconf.ssh.address=0.0.0.0
 netconf.ssh.port=1830
 netconf.ssh.pk.path = ./configuration/RSA.pk
+netconf.ssh.default.user = netconf
+netconf.ssh.default.password = netconf
 
 
 netconf.config.persister.active=1,2
index 619ab06d8d3c3da7ca181949b4fff7ddd7596e6e..d872bfd47b229c4047d0bcfb05e98034474e93d3 100644 (file)
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
                     <name>yang-schema-service</name>
                 </module>
-                <!-- To enable use of new in-memory datastore and new implementations
-                     of data brokers, comment out all parts of this
-                     xml which are marked with DATA-BROKER and uncomment all parts
-                     of this xml which are marked with NEW-DATA-BROKER
-                -->
-                <!-- DATA-BROKER start-->
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
-                    <name>hash-map-data-store</name>
-                </module>
-                <!-- DATA BROKER end -->
-                <!-- NEW-DATA-BROKER start -->
-                <!--
                 <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
-                    <name>async-data-broker</name>
-                    <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>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+                    <name>runtime-mapping-singleton</name>
                 </module>
-                -->
-                <!-- NEW-DATA-BROKER end -->
                 <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
-                    <name>dom-broker</name>
-                    <!-- DATA-BROKER start -->
-                    <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
-                        <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
-                        <name>hash-map-data-store</name>
-                        <!-- <name>cluster-data-store</name> -->
-                    </data-store>
-                    <!-- DATA-BROKER end -->
-                    <!-- NEW-DATA-BROKER start -->
-                    <!--
-                    <async-data-broker>
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
-                        <name>async-data-broker</name>
-                    </async-data-broker>
-                    -->
-                    <!-- NEW-DATA-BROKER end -->
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+                    <name>binding-notification-broker</name>
                 </module>
                 <module>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
                         <name>binding-data-broker</name>
                     </data-broker>
                 </module>
+
+                <!--
+                     Tree-based in-memory data store. This is the data store which is currently
+                     recommended for single-node deployments.
+                -->
                 <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
-                    <name>runtime-mapping-singleton</name>
-                </module>
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
-                    <name>binding-notification-broker</name>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
+                    <name>inmemory-data-broker</name>
+                    <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>
-                <!-- DATA-BROKER start -->
                 <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
-                    <name>binding-data-broker</name>
-                    <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
-                        <name>dom-broker</name>
-                    </dom-broker>
-                    <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
-                        <name>runtime-mapping-singleton</name>
-                    </mapping-service>
+                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+                    <name>inmemory-dom-broker</name>
+                    <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>
                 </module>
-                <!-- DATA-BROKER end -->
-                <!-- NEW-DATA-BROKER start -->
-                <!--
                 <module>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
-                    <name>binding-data-broker</name>
+                    <name>inmemory-binding-data-broker</name>
                     <dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
                         <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
                         <name>dom-broker</name>
                         <name>runtime-mapping-singleton</name>
                     </binding-mapping-service>
                 </module>
-                -->
-                <!-- NEW-DATA-BROKER end -->
             </modules>
             <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <service>
-                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
-                    <instance>
-                        <name>yang-schema-service</name>
-                        <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
-                    <instance>
-                        <name>binding-notification-broker</name>
-                        <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
-                    </instance>
-                </service>
-                <!-- DATA-BROKER start -->
-                <service>
-                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
-                    <instance>
-                        <name>hash-map-data-store</name>
-                        <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
-                    </instance>
-                </service>
-                <!-- DATA-BROKER end -->
-                <!-- NEW-DATA-BROKER start -->
-                <!--
-                <service>
-                    <type  xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
-                    <instance>
-                        <name>async-data-broker</name>
-                        <provider>/modules/module[type='dom-inmemory-data-broker'][name='async-data-broker']</provider>
-                    </instance>
-                </service>
-                -->
-                <!-- NEW-DATA-BROKER end -->
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
-                    <instance>
-                        <name>binding-osgi-broker</name>
-                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
-                    <instance>
-                        <name>binding-rpc-broker</name>
-                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
-                    <instance>
-                        <name>runtime-mapping-singleton</name>
-                        <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
-                    </instance>
-                </service>
-                <service>
-                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
-                    <instance>
-                        <name>dom-broker</name>
-                        <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
-                    </instance>
-                </service>
+                    <service>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+                        <instance>
+                            <name>yang-schema-service</name>
+                            <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
+                        </instance>
+                    </service>
+                    <service>
+                        <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+                        <instance>
+                            <name>runtime-mapping-singleton</name>
+                            <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
+                        </instance>
+                    </service>
+                    <service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+                        <instance>
+                            <name>binding-notification-broker</name>
+                            <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+                        </instance>
+                    </service>
+                    <service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+                        <instance>
+                            <name>binding-osgi-broker</name>
+                            <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                        </instance>
+                    </service>
+                    <service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                        <instance>
+                            <name>binding-rpc-broker</name>
+                            <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                        </instance>
+                    </service>
 
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
-                    <instance>
-                        <name>binding-data-broker</name>
-                        <!--  DATA-BROKER start -->
-                        <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
-                        <!--  DATA-BROKER end -->
-                        <!-- NEW-DATA-BROKER start -->
-                        <!--
-                        <provider>/modules/module[type='binding-data-compatible-broker'][name='binding-data-broker']</provider>
-                        -->
-                        <!--  NEW-DATA-BROKER end -->
-                    </instance>
-                </service>
+                    <service>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                        <instance>
+                            <name>dom-broker</name>
+                            <provider>/modules/module[type='dom-broker-impl'][name='inmemory-dom-broker']</provider>
+                        </instance>
+                    </service>
 
+                    <service>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                        <instance>
+                            <name>binding-data-broker</name>
+                            <provider>/modules/module[type='binding-data-compatible-broker'][name='inmemory-binding-data-broker']</provider>
+                        </instance>
+                    </service>
+
+                    <service>
+                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+                        <instance>
+                            <name>inmemory-data-broker</name>
+                            <provider>/modules/module[type='dom-inmemory-data-broker'][name='inmemory-data-broker']</provider>
+                        </instance>
+                    </service>
             </services>
         </data>
     </configuration>
diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-netconf-connector.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-netconf-connector.xml
new file mode 100644 (file)
index 0000000..fcbec19
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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>
+  <configuration>
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+        <!-- Netconf dispatcher to be used by all netconf-connectors --> 
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">prefix:netconf-client-dispatcher</type>
+          <name>global-netconf-dispatcher</name>
+          <boss-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
+            <name>global-boss-group</name>
+          </boss-thread-group>
+          <worker-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
+            <name>global-worker-group</name>
+          </worker-thread-group>
+          <timer xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher">
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-timer</type>
+            <name>global-timer</name>
+          </timer>
+        </module>  
+
+        <!-- Loopback connection to netconf server in controller using netconf-connector -->
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">prefix:sal-netconf-connector</type>
+          <name>controller-config</name>
+          <address xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">127.0.0.1</address>
+          <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">1830</port>
+          <username xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</username>
+          <password xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</password>
+          <tcp-only xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">false</tcp-only>
+          <event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-event-executor</type>
+            <name>global-event-executor</name>
+          </event-executor>
+          <dom-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+            <name>dom-broker</name>
+          </dom-registry>
+          <client-dispatcher xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf">prefix:netconf-client-dispatcher</type>
+            <name>global-netconf-dispatcher</name>
+          </client-dispatcher>
+        </module>
+      </modules>
+
+      <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <service>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf">prefix:netconf-client-dispatcher</type>
+          <instance>
+            <name>global-netconf-dispatcher</name>
+            <provider>/modules/module[type='netconf-client-dispatcher'][name='global-netconf-dispatcher']</provider>
+          </instance>
+        </service>
+      </services>
+
+    </data>
+  </configuration>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf?module=odl-sal-netconf-connector-cfg&amp;revision=2013-10-28</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher?module=odl-netconfig-client-cfg&amp;revision=2014-04-08</capability>
+  </required-capabilities>
+</snapshot>
diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/04-netconf-connector.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/04-netconf-connector.xml
deleted file mode 100644 (file)
index 8143a38..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
- 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>
-  <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:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">prefix:sal-netconf-connector</type>
-      <name>controller-config</name>
-      <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">1830</port>
-      <username xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</username>
-      <worker-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
-        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
-        <name>global-worker-group</name>
-      </worker-thread-group>
-      <address xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">127.0.0.1</address>
-      <tcp-only xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">false</tcp-only>
-      <event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
-        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-event-executor</type>
-        <name>global-event-executor</name>
-      </event-executor>
-      <password xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">admin</password>
-      <boss-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
-        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
-        <name>global-boss-group</name>
-      </boss-thread-group>
-      <dom-registry xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf">
-        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
-        <name>dom-broker</name>
-      </dom-registry>
-    </module>
-      </modules>
-    </data>
-  </configuration>
-  <required-capabilities>
-      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf?module=odl-sal-netconf-connector-cfg&amp;revision=2013-10-28</capability>
-  </required-capabilities>
-</snapshot>
index 93ce0dd4f7161874ec6d7954e4a4729befdec461..7770c153498fe8a4491e81785236d3e2f21d25bd 100644 (file)
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.eclipse.xtend</groupId>
-      <artifactId>org.eclipse.xtend.lib</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>forwardingrulesmanager</artifactId>
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.eclipse.xtend</groupId>
-        <artifactId>xtend-maven-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
   <scm>
diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/ConfigurationReader.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/ConfigurationReader.java
new file mode 100644 (file)
index 0000000..411af28
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * 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.frm.compatibility;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.sal.compatibility.NodeMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.FlowsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigurationReader implements FlowManagementReader {
+
+    private final static Logger LOG = LoggerFactory.getLogger(ConfigurationReader.class);
+
+    private IForwardingRulesManager manager;
+
+    @Override
+    public Flows readAllFlows() {
+        List<FlowConfig> staticFlows = this.manager.getStaticFlows();
+        List<Flow> flowMap = new ArrayList<Flow>(staticFlows.size());
+
+        for (FlowConfig conf : staticFlows) {
+            flowMap.add(FlowConfigMapping.toConfigurationFlow(conf));
+        }
+        final FlowsBuilder flowsBuilder = new FlowsBuilder();
+        return (flowsBuilder.setFlow(flowMap)).build();
+    }
+
+    @Override
+    public Flow readFlow(final FlowKey key) {
+        try {
+            final FlowConfig flowConf =
+                    this.manager.getStaticFlow(String.valueOf(key.getId()), NodeMapping.toADNode(key.getNode()));
+            return FlowConfigMapping.toConfigurationFlow(flowConf);
+        } catch (Exception e) {
+            String errMsg = MessageFormat.format("readFlow by key {} fail", key);
+            LOG.error(errMsg, e);
+            throw new RuntimeException(errMsg, e);
+        }
+    }
+
+    public IForwardingRulesManager getManager() {
+        return this.manager;
+    }
+
+    public void setManager(final IForwardingRulesManager manager) {
+        this.manager = manager;
+    }
+}
diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.java
new file mode 100644 (file)
index 0000000..be3add1
--- /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.md.frm.compatibility;
+
+import java.util.Collections;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
+import org.opendaylight.controller.sal.common.util.Arguments;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+
+public class FRMRuntimeDataProvider implements RuntimeDataProvider, DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject> {
+
+    private final static InstanceIdentifier<Flows> FLOWS_PATH = InstanceIdentifier.<Flows> builder(Flows.class).toInstance();
+
+    private final FlowManagementReader configuration = new ConfigurationReader();
+    private DataChangeListener<InstanceIdentifier<? extends DataObject>, DataObject> changeListener;
+    private DataProviderService dataService;
+    private IForwardingRulesManager manager;
+
+    public Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> init() {
+        return this.dataService.registerCommitHandler(FRMRuntimeDataProvider.FLOWS_PATH, this);
+    }
+
+    @Override
+    public DataObject readConfigurationData(final InstanceIdentifier<? extends DataObject> path) {
+        return this.readFrom(this.configuration, path);
+    }
+
+    @Override
+    public DataObject readOperationalData(final InstanceIdentifier<? extends DataObject> path) {
+        return this.readFrom(this.configuration, path);
+    }
+
+    public DataObject readFrom(final FlowManagementReader store, final InstanceIdentifier<? extends DataObject> path) {
+        if (Objects.equal(FRMRuntimeDataProvider.FLOWS_PATH, path)) {
+            return store.readAllFlows();
+        }
+        if (FRMRuntimeDataProvider.FLOWS_PATH.contains(path)) {
+            return store.readFlow(this.toFlowKey(path));
+        }
+        return null;
+    }
+
+    @Override
+    public FlowCommitTransaction requestCommit(final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
+        return new FlowCommitTransaction(this, modification);
+    }
+
+    public FlowKey toFlowKey(final InstanceIdentifier<? extends DataObject> identifier) {
+        Preconditions.<InstanceIdentifier<? extends DataObject>> checkNotNull(identifier);
+
+        Iterable<PathArgument> path = identifier.getPathArguments();
+        PathArgument get = path.iterator().next();
+        final Identifier itemKey = Arguments.<IdentifiableItem> checkInstanceOf(get, IdentifiableItem.class).getKey();
+        return Arguments.<FlowKey> checkInstanceOf(itemKey, FlowKey.class);
+    }
+
+    public RpcResult<Void> finish(final FlowCommitTransaction transaction) {
+        Iterable<FlowConfig> toRemove = transaction.getToRemove();
+        for (final FlowConfig flow : toRemove) {
+            this.manager.removeStaticFlow(flow.getName(), flow.getNode());
+        }
+        Iterable<FlowConfig> toUpdate = transaction.getToUpdate();
+        for (final FlowConfig flow : toUpdate) {
+            this.manager.removeStaticFlow(flow.getName(), flow.getNode());
+            this.manager.addStaticFlow(flow);
+        }
+        return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
+    }
+
+    public RpcResult<Void> rollback(final FlowCommitTransaction transaction) {
+        return null;
+    }
+
+    public DataProviderService getDataService() {
+        return this.dataService;
+    }
+
+    public void setDataService(final DataProviderService dataService) {
+        this.dataService = dataService;
+    }
+
+    public DataChangeListener<InstanceIdentifier<? extends DataObject>, DataObject> getChangeListener() {
+        return this.changeListener;
+    }
+
+    public void setChangeListener(final DataChangeListener<InstanceIdentifier<? extends DataObject>, DataObject> changeListener) {
+        this.changeListener = changeListener;
+    }
+
+    public IForwardingRulesManager getManager() {
+        return this.manager;
+    }
+
+    public void setManager(final IForwardingRulesManager manager) {
+        this.manager = manager;
+    }
+}
diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FRMRuntimeDataProvider.xtend
deleted file mode 100644 (file)
index 2d4e7d2..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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.frm.compatibility
-
-import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.Flows
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.FlowsBuilder
-import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager
-import static com.google.common.base.Preconditions.*;
-import static extension org.opendaylight.controller.md.frm.compatibility.FlowConfigMapping.*;
-import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*;
-import org.opendaylight.controller.sal.common.util.Arguments
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.opendaylight.controller.forwardingrulesmanager.FlowConfig
-import java.util.HashSet
-import org.opendaylight.controller.sal.common.util.Rpcs
-import java.util.Collections
-import org.opendaylight.yangtools.yang.common.RpcError
-
-class FRMRuntimeDataProvider implements RuntimeDataProvider, DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-
-    static val FLOWS_PATH = InstanceIdentifier.builder(Flows).toInstance;
-
-    @Property
-    var DataProviderService dataService;
-
-    @Property
-    var DataChangeListener changeListener;
-    
-    @Property
-    var IForwardingRulesManager manager;
-
-    FlowManagementReader configuration = new ConfigurationReader();
-
-    def init() {
-        //dataService.registerDataChangeListener(FLOWS_PATH, changeListener);
-        dataService.registerCommitHandler(FLOWS_PATH, this);
-    }
-
-    override readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
-        return readFrom(configuration, path);
-    }
-
-    override DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
-        return readFrom(configuration, path);
-    }
-
-    def DataObject readFrom(FlowManagementReader store, InstanceIdentifier<? extends DataObject> path) {
-        if (FLOWS_PATH == path) {
-            return store.readAllFlows();
-        }
-        if (FLOWS_PATH.contains(path)) {
-            return store.readFlow(path.toFlowKey());
-        }
-        return null;
-    }
-
-    override FlowCommitTransaction requestCommit(
-        DataModification modification) {
-        return new FlowCommitTransaction(this,modification);
-    }
-
-    def toFlowKey(InstanceIdentifier<? extends DataObject> identifier) {
-        checkNotNull(identifier)
-        val item = Arguments.checkInstanceOf(identifier.path.get(1),IdentifiableItem);
-        val key = Arguments.checkInstanceOf(item.key,FlowKey)
-        return key;
-    }
-    
-    def RpcResult<Void> finish(FlowCommitTransaction transaction) {
-        for(flw: transaction.toRemove) {
-            manager.removeStaticFlow(flw.name,flw.node)
-        }
-        
-        for(flw: transaction.toUpdate) {
-            manager.removeStaticFlow(flw.name,flw.node);
-            manager.addStaticFlow(flw);
-        }
-        
-        return Rpcs.<Void>getRpcResult(true,null,Collections.<RpcError>emptySet())
-    }
-    
-    def RpcResult<Void> rollback(FlowCommitTransaction transaction) {
-        // NOOP: We did not changed any state.
-    }
-
-}
-
-class ConfigurationReader implements FlowManagementReader {
-
-    @Property
-    var IForwardingRulesManager manager;
-
-    override Flows readAllFlows() {
-        val it = new FlowsBuilder();
-        flow = manager.staticFlows.map[
-            toConfigurationFlow();
-        ]
-        return it.build();
-    }
-
-    override readFlow(FlowKey key) {
-        val flowCfg = manager.getStaticFlow(String.valueOf(key.id), key.node.toADNode());
-        return flowCfg.toConfigurationFlow;
-    }
-}
-
-public static class FlowCommitTransaction implements DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
-
-    @Property
-    val DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
-
-    @Property
-    val FRMRuntimeDataProvider flowManager;
-    
-    @Property
-    val toAdd = new HashSet<FlowConfig>();
-    
-    @Property
-    var Iterable<FlowConfig> toUpdate
-    
-    @Property
-    var Iterable<FlowConfig> toRemove
-    
-
-    new(FRMRuntimeDataProvider flowManager,DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
-        super();
-        _flowManager = flowManager;
-        _modification = modification;
-        processModification();
-    }
-
-    override finish() throws IllegalStateException {
-        return flowManager.finish(this);
-    }
-
-    override rollback() throws IllegalStateException
-{
-        return flowManager.rollback(this);
-    }
-
-    def processModification() {
-        val updated = modification.updatedConfigurationData.entrySet;
-        
-        val _toUpdate = updated.filter[key.isFlowPath].map[
-             return (value as Flow).toFlowConfig
-        ]
-        toUpdate = _toUpdate as Iterable<FlowConfig>
-        
-        
-        val _toRemove = modification.removedConfigurationData.filter[isFlowPath].map[
-             toFlowConfig
-        ]
-        toRemove = _toRemove as Iterable<FlowConfig>
-        
-    }
-}
diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowCommitTransaction.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowCommitTransaction.java
new file mode 100644 (file)
index 0000000..bf0050d
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * 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.frm.compatibility;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class FlowCommitTransaction implements DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
+
+    private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
+    private final HashSet<FlowConfig> toAdd = new HashSet<FlowConfig>();
+    private final FRMRuntimeDataProvider flowManager;
+    private Iterable<FlowConfig> toUpdate;
+    private Iterable<FlowConfig> toRemove;
+
+    public FlowCommitTransaction(
+            final FRMRuntimeDataProvider flowManager,
+            final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
+        this.flowManager = flowManager;
+        this.modification = modification;
+        this.processModification();
+    }
+
+    @Override
+    public RpcResult<Void> finish() throws IllegalStateException {
+        return this.flowManager.finish(this);
+    }
+
+    @Override
+    public RpcResult<Void> rollback() throws IllegalStateException {
+        return this.flowManager.rollback(this);
+    }
+
+    public void processModification() {
+        final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updated =
+                this.modification.getUpdatedConfigurationData().entrySet();
+        final List<FlowConfig> forUpdate = new ArrayList<FlowConfig>(updated.size());
+
+        if (updated != null && !(updated.isEmpty())) {
+            for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : updated) {
+                if (FlowConfigMapping.isFlowPath(entry.getKey())) {
+                    forUpdate.add(FlowConfigMapping.toFlowConfig((Flow) entry.getValue()));
+                }
+            }
+        }
+        this.toUpdate = Collections.unmodifiableCollection(forUpdate);
+
+        final Set<InstanceIdentifier<? extends DataObject>> removedConfigurationData =
+                this.modification.getRemovedConfigurationData();
+        final List<FlowConfig> forRemove = new ArrayList<FlowConfig>(removedConfigurationData.size());
+
+        if (removedConfigurationData != null && !(removedConfigurationData.isEmpty())) {
+            for (InstanceIdentifier<? extends DataObject> data : removedConfigurationData) {
+                if (FlowConfigMapping.isFlowPath(data)) {
+                    forRemove.add(FlowConfigMapping.toFlowConfig(data));
+                }
+            }
+        }
+        this.toRemove = Collections.unmodifiableCollection(forRemove);
+    }
+
+    @Override
+    public DataModification<InstanceIdentifier<? extends DataObject>, DataObject> getModification() {
+        return this.modification;
+    }
+
+    public FRMRuntimeDataProvider getFlowManager() {
+        return this.flowManager;
+    }
+
+    public HashSet<FlowConfig> getToAdd() {
+        return this.toAdd;
+    }
+
+    public Iterable<FlowConfig> getToUpdate() {
+        return this.toUpdate;
+    }
+
+    public Iterable<FlowConfig> getToRemove() {
+        return this.toRemove;
+    }
+}
diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.java b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.java
new file mode 100644 (file)
index 0000000..58c60ec
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * 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.frm.compatibility;
+
+import java.text.MessageFormat;
+import java.util.Iterator;
+
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.sal.compatibility.MDFlowMapping;
+import org.opendaylight.controller.sal.compatibility.NodeMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAdded;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowConfigMapping {
+
+    private final static Logger LOG = LoggerFactory.getLogger(FlowConfigMapping.class);
+
+    /* nodes/node/flow  -> 0 / 1 / 2  */
+    private static final int FLOW_KEY_IDENTIFIER_DEEP = 2;
+
+    public static Flow toConfigurationFlow(final FlowConfig sourceCfg) {
+        final FlowAdded source = MDFlowMapping.flowAdded(sourceCfg.getFlow());
+        final FlowBuilder flowBuilder = new FlowBuilder();
+        flowBuilder.setInstructions(source.getInstructions());
+        flowBuilder.setCookie(source.getCookie());
+        flowBuilder.setHardTimeout(source.getHardTimeout());
+        flowBuilder.setIdleTimeout(source.getIdleTimeout());
+        flowBuilder.setMatch(source.getMatch());
+        flowBuilder.setNode(source.getNode());
+
+        FlowKey flowKey =
+                new FlowKey(Long.valueOf(sourceCfg.getName()), flowBuilder.getNode());
+        flowBuilder.setKey(flowKey);
+        return flowBuilder.build();
+    }
+
+    public static FlowConfig toFlowConfig(final Flow sourceCfg) {
+        try {
+            final FlowConfig flowConfig = new FlowConfig();
+            flowConfig.setName(String.valueOf(sourceCfg.getId()));
+            flowConfig.setNode(NodeMapping.toADNode(sourceCfg.getNode()));
+            return flowConfig;
+        } catch (Exception e) {
+            String errMsg = MessageFormat.format("Convert from Flow {} to FlowConfig fail", sourceCfg);
+            LOG.error(errMsg, e);
+            throw new RuntimeException(errMsg, e);
+        }
+    }
+
+    public static FlowConfig toFlowConfig(final InstanceIdentifier<? extends Object> identifier) {
+        try {
+            PathArgument pathArg = FlowConfigMapping.getSecondPathArgumentFromPath(identifier);
+            if (pathArg != null) {
+                final FlowConfig flowConfig = new FlowConfig();
+                FlowKey key = ((IdentifiableItem<Flow, FlowKey>) pathArg).getKey();
+                flowConfig.setName(String.valueOf(key.getId()));
+                flowConfig.setNode(NodeMapping.toADNode(key.getNode()));
+                return flowConfig;
+            }
+            return null;
+        } catch (Exception e) {
+            String errMsg = MessageFormat.format("Convert from InstanceIdentifier {} to FlowConfig fail", identifier);
+            LOG.error(errMsg, e);
+            throw new RuntimeException(errMsg, e);
+        }
+    }
+
+    public static boolean isFlowPath(final InstanceIdentifier<? extends Object> path) {
+        PathArgument pathArg = FlowConfigMapping.getSecondPathArgumentFromPath(path);
+        if (pathArg == null) {
+            return false;
+        }
+        if (pathArg instanceof IdentifiableItem<?,?>) {
+            final Identifiable<?> key = ((IdentifiableItem<?, ? extends Identifiable<?>>) pathArg).getKey();
+            if ((key instanceof FlowKey)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static PathArgument getSecondPathArgumentFromPath(final InstanceIdentifier<? extends Object> path) {
+        if (path != null && path.getPathArguments() != null) {
+            Iterator<PathArgument> iterator = path.getPathArguments().iterator();
+            int deep = 0;
+            while (iterator.hasNext()) {
+                PathArgument pathArg = iterator.next();
+                if (deep == FlowConfigMapping.FLOW_KEY_IDENTIFIER_DEEP) {
+                    return pathArg;
+                }
+                deep++;
+            }
+        }
+        return null;
+    }
+}
diff --git a/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend b/opendaylight/md-sal/compatibility/flow-management-compatibility/src/main/java/org/opendaylight/controller/md/frm/compatibility/FlowConfigMapping.xtend
deleted file mode 100644 (file)
index e15b3c6..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.frm.compatibility
-
-import org.opendaylight.controller.forwardingrulesmanager.FlowConfig
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowBuilder
-
-import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
-import static org.opendaylight.controller.sal.compatibility.MDFlowMapping.*
-import static org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils.*
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.FlowKey
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
-import org.opendaylight.yangtools.yang.binding.Identifiable
-
-class FlowConfigMapping {
-
-    static def toConfigurationFlow(FlowConfig sourceCfg) {
-        val source = flowAdded(sourceCfg.flow);
-        val it = new FlowBuilder();
-        instructions = source.instructions;
-        cookie = source.cookie;
-        hardTimeout = source.hardTimeout
-        idleTimeout = source.idleTimeout
-        match = source.match
-        node = source.node
-        key = new FlowKey(Long.parseLong(sourceCfg.name),node);
-        return it.build();
-    }
-
-    static def toFlowConfig(Flow sourceCfg) {
-        val it = new FlowConfig;
-        name = String.valueOf(sourceCfg.id);
-        node = sourceCfg.node.toADNode();
-
-        return it
-    }
-
-    static def toFlowConfig(InstanceIdentifier<?> identifier) {
-        val it = new FlowConfig()
-        val FlowKey key = ((identifier.path.get(2) as IdentifiableItem<Flow,FlowKey>).key)
-        name = String.valueOf(key.id);
-        node = key.node.toADNode();
-
-        return it;
-    }
-
-    static def boolean isFlowPath(InstanceIdentifier<?> path) {
-        if(path.path.size < 2) return false;
-        if (path.path.get(2) instanceof IdentifiableItem<?,?>) {
-            val IdentifiableItem<?,? extends Identifiable<?>> item = path.path.get(2) as IdentifiableItem<?,? extends Identifiable<?>>;
-            val Identifiable<?> key = item.key;
-            if (key instanceof FlowKey) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyCommitHandler.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyCommitHandler.java
new file mode 100644 (file)
index 0000000..a35c3ed
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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.sal.compatibility.topology;
+
+import static org.opendaylight.controller.sal.compatibility.topology.TopologyMapping.toAdEdge;
+import static org.opendaylight.controller.sal.compatibility.topology.TopologyMapping.toTopoEdgeUpdate;
+
+import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.topology.IPluginOutTopologyService;
+import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TopologyCommitHandler implements DataChangeListener {
+    private static final Logger LOG = LoggerFactory.getLogger(TopologyCommitHandler.class);
+
+    private IPluginOutTopologyService topologyPublisher;
+
+    private final DataProviderService dataService;
+
+    public TopologyCommitHandler(final DataProviderService dataService, final IPluginOutTopologyService topologyPub) {
+        this.topologyPublisher = topologyPub;
+        this.dataService = dataService;
+    }
+
+    @Override
+    public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> modification) {
+        CopyOnWriteArrayList<TopoEdgeUpdate> msg = new CopyOnWriteArrayList<TopoEdgeUpdate>();
+        try {
+            TypeSafeDataReader reader = TypeSafeDataReader.forReader(dataService);
+            InstanceIdentifier<Topology> topologyPath = InstanceIdentifier.builder(NetworkTopology.class)
+                    .child(Topology.class, new TopologyKey(new TopologyId("flow:1"))).build();
+            Topology topology = reader.readOperationalData(topologyPath);
+
+            for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : modification
+                    .getCreatedOperationalData().entrySet()) {
+                if (entry.getValue() instanceof Link
+                        && modification.getCreatedOperationalData().containsKey(entry.getKey())) {
+                    msg.add(toTopoEdgeUpdate(toAdEdge((Link) entry.getValue(), topology), UpdateType.ADDED, reader));
+                }
+            }
+
+            for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : modification
+                    .getUpdatedOperationalData().entrySet()) {
+                if (entry.getValue() instanceof Link) {
+                    msg.add(toTopoEdgeUpdate(toAdEdge((Link) entry.getValue(), topology), UpdateType.CHANGED, reader));
+                }
+            }
+            for (InstanceIdentifier<? extends DataObject> path : modification.getRemovedOperationalData()) {
+                if (path.getTargetType() == Link.class) {
+                    Link link = (Link) modification.getOriginalOperationalData().get(path);
+                    msg.add(toTopoEdgeUpdate(toAdEdge(link, topology), UpdateType.CHANGED, reader));
+                }
+
+            }
+
+            if (topologyPublisher != null && msg != null && !msg.isEmpty()) {
+                topologyPublisher.edgeUpdate(msg);
+            }
+
+        } catch (Exception e) {
+            LOG.error("Exception caught", e);
+        }
+    }
+
+    protected IPluginOutTopologyService getTopologyPublisher() {
+        return topologyPublisher;
+    }
+
+    protected void setTopologyPublisher(final IPluginOutTopologyService topologyPublisher) {
+        this.topologyPublisher = topologyPublisher;
+    }
+
+}
diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyCommitHandler.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyCommitHandler.xtend
deleted file mode 100644 (file)
index fcf86f2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.sal.compatibility.topology
-
-import com.google.common.collect.FluentIterable
-import java.util.concurrent.CopyOnWriteArrayList
-import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.core.UpdateType
-import org.opendaylight.controller.sal.topology.IPluginOutTopologyService
-import org.opendaylight.controller.sal.topology.TopoEdgeUpdate
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import static extension org.opendaylight.controller.sal.compatibility.topology.TopologyMapping.*
-import org.slf4j.LoggerFactory
-
-class TopologyCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-    static val LOG = LoggerFactory.getLogger(TopologyCommitHandler);
-    @Property
-    IPluginOutTopologyService topologyPublisher;
-    
-    @Property
-    DataProviderService dataService;
-    
-    new(DataProviderService dataService) {
-        _topologyPublisher = topologyPublisher
-        _dataService = dataService
-    }
-    
-    override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
-        val msg = new CopyOnWriteArrayList<TopoEdgeUpdate>()
-        try {
-            val reader = TypeSafeDataReader.forReader(dataService)
-            val topologyPath = InstanceIdentifier.builder(NetworkTopology).child(Topology, new TopologyKey(new TopologyId("flow:1"))).toInstance
-            val topology = reader.readOperationalData(topologyPath)
-            val adds = FluentIterable.from(modification.createdOperationalData.entrySet)
-                .filter[value instanceof Link]
-                .transform[(value as Link).toAdEdge(topology).toTopoEdgeUpdate(UpdateType.ADDED,reader)]
-                .toList
-            val updates = FluentIterable.from(modification.updatedOperationalData.entrySet)
-                .filter[!modification.createdOperationalData.containsKey(key) && (value instanceof Link)]
-                .transform[(value as Link).toAdEdge(topology).toTopoEdgeUpdate(UpdateType.ADDED,reader)] // Evidently the ADSAL does not expect edge 'CHANGED"
-                .toList
-            val removes = FluentIterable.from(modification.removedOperationalData)
-                .transform[reader.readOperationalData(it as InstanceIdentifier<DataObject>)]
-                .filter[it instanceof Link]
-                .transform[(it as Link).toAdEdge(topology).toTopoEdgeUpdate(UpdateType.REMOVED,reader)]
-                .toList
-            msg.addAll(adds)
-            msg.addAll(updates)
-            msg.addAll(removes)
-         } catch (Exception e) {
-            LOG.error("Exception caught",e)
-         }
-        return new TopologyTransaction(modification,topologyPublisher,dataService,msg)
-    }
-}
index 4aef75d9916565dc20c3c18a87149669116f4753..21f2b35f40a82c846df07e7ce05fab2ae540029c 100644 (file)
@@ -15,10 +15,10 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey
 import org.opendaylight.yangtools.yang.binding.DataObject
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link
 import org.slf4j.LoggerFactory
+import org.opendaylight.yangtools.concepts.ListenerRegistration
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
 
 class TopologyProvider implements AutoCloseable{
     static val LOG = LoggerFactory.getLogger(TopologyProvider);
@@ -30,8 +30,9 @@ class TopologyProvider implements AutoCloseable{
     @Property
     DataProviderService dataService;
     
-    Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-
+    ListenerRegistration<DataChangeListener> listenerRegistration
+    
+    
     def void start() {
 
     }
@@ -40,18 +41,17 @@ class TopologyProvider implements AutoCloseable{
             LOG.error("dataService not set");
             return;
         }
-        commitHandler = new TopologyCommitHandler(dataService)
-        commitHandler.setTopologyPublisher(topologyPublisher)
+        commitHandler = new TopologyCommitHandler(dataService,topologyPublisher);
         val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(NetworkTopology)
             .child(Topology,new TopologyKey(new TopologyId("flow:1")))
             .child(Link)
             .toInstance();
-        commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
+        listenerRegistration = dataService.registerDataChangeListener(path,commitHandler);
         LOG.info("TopologyProvider started")
     }
     
     override close() throws Exception {
-        commitHandlerRegistration.close
+        listenerRegistration.close
     }
     
     def setTopologyPublisher(IPluginOutTopologyService topologyPublisher) {
diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyTransaction.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/topology/TopologyTransaction.xtend
deleted file mode 100644 (file)
index 4de78ca..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.sal.compatibility.topology
-
-import java.util.Collections
-import java.util.List
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.topology.IPluginOutTopologyService
-import org.opendaylight.controller.sal.topology.TopoEdgeUpdate
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.slf4j.LoggerFactory
-
-class TopologyTransaction implements DataCommitTransaction<InstanceIdentifier<?extends DataObject>, DataObject> {
-    static val LOG = LoggerFactory.getLogger(TopologyTransaction);
-    @Property
-    val DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
-    
-    @Property
-    IPluginOutTopologyService topologyPublisher;
-    
-    @Property
-    DataProviderService dataService;
-    @Property
-    List<TopoEdgeUpdate> edgeUpdates;
-    
-    new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,IPluginOutTopologyService topologyPublisher,
-        DataProviderService dataService,List<TopoEdgeUpdate> edgeUpdates) {
-        _modification = modification;
-        _topologyPublisher = topologyPublisher
-        _dataService = dataService
-        _edgeUpdates = edgeUpdates
-    }
-    override finish() throws IllegalStateException {
-        
-        if(topologyPublisher != null && _edgeUpdates != null && !edgeUpdates.empty) {
-            topologyPublisher.edgeUpdate(edgeUpdates)
-        }
-         
-         return new RpcResultTo()
-    }
-    
-    override getModification() {
-        return _modification;
-    }
-    
-    override rollback() throws IllegalStateException {
-        // NOOP
-    }
-}
-class RpcResultTo implements RpcResult<Void> {
-    
-    override getErrors() {
-        return Collections.emptySet
-    }
-    
-    override getResult() {
-        return null;
-    }
-    
-    override isSuccessful() {
-        return true;
-    }
-    
-}
index 919a53c3643c406fbe8cfabfc595adfff950f204..9bd63d3c3bb5268d8d6e5142dd38da888a90b906 100644 (file)
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.eclipse.xtend</groupId>
-        <artifactId>xtend-maven-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
 
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java
new file mode 100644 (file)
index 0000000..426f4ba
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * 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.frm;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * 
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public abstract class AbstractChangeListener implements DataChangeListener {
+
+    private final AtomicLong txNum = new AtomicLong();
+    private String transactionId;
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+        this.transactionId = this.newTransactionIdentifier().toString();
+
+        final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = 
+                changeEvent.getCreatedConfigurationData().entrySet();
+        final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = 
+                new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
+
+        Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updateConfigEntrySet = 
+                changeEvent.getUpdatedConfigurationData().entrySet();
+        updatedEntries.addAll(updateConfigEntrySet);
+        updatedEntries.removeAll(createdEntries);
+
+        final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = 
+                changeEvent.getRemovedConfigurationData();
+
+        for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
+            InstanceIdentifier<? extends DataObject> c_key = createdEntry.getKey();
+            DataObject c_value = createdEntry.getValue();
+            this.add(c_key, c_value);
+        }
+
+        for (final Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
+            Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData = 
+                    changeEvent.getOriginalConfigurationData();
+
+            InstanceIdentifier<? extends Object> u_key = updatedEntrie.getKey();
+            final DataObject originalFlow = origConfigData.get(u_key);
+            final DataObject updatedFlow = updatedEntrie.getValue();
+            this.update(u_key, originalFlow, updatedFlow);
+        }
+
+        for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
+            Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData = 
+                    changeEvent.getOriginalConfigurationData();
+
+            final DataObject removeValue = origConfigData.get(instanceId);
+            this.remove(instanceId, removeValue);
+        }
+    }
+
+    public String getTransactionId() {
+        return this.transactionId;
+    }
+
+    private Object newTransactionIdentifier() {
+        return "DOM-" + txNum.getAndIncrement();
+    }
+
+    protected abstract void validate() throws IllegalStateException;
+
+    protected abstract void remove(
+            final InstanceIdentifier<? extends DataObject> identifier,
+            final DataObject remove);
+
+    protected abstract void update(
+            final InstanceIdentifier<? extends DataObject> identifier,
+            final DataObject original, final DataObject update);
+
+    protected abstract void add(
+            final InstanceIdentifier<? extends DataObject> identifier,
+            final DataObject add);
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractTransaction.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractTransaction.xtend
deleted file mode 100644 (file)
index cb1e90d..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.frm
-
-import java.util.Collections
-import java.util.HashSet
-import java.util.Map.Entry
-import java.util.Set
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.controller.sal.common.util.Rpcs
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.common.RpcError
-
-abstract class AbstractTransaction implements DataCommitTransaction<InstanceIdentifier<?extends DataObject>, DataObject> {
-        
-    @Property
-    val DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
-    
-    new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
-        _modification = modification;
-    }
-    
-    def void validate() throws IllegalStateException
-    
-    override finish() throws IllegalStateException {
-        validate()
-        callRpcs();
-        return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());     
-    }
-    
-    override getModification() {
-        return _modification;
-    }
-    
-    override rollback() throws IllegalStateException {
-        rollbackRpcs();
-        return Rpcs.getRpcResult(true, null, Collections.<RpcError>emptySet());
-    }
-    
-    def private callRpcs() {
-        val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = _modification.getCreatedConfigurationData().entrySet();
-
-        /*
-         * This little dance is because updatedEntries contains both created and modified entries
-         * The reason I created a new HashSet is because the collections we are returned are immutable.
-         */
-        val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
-        updatedEntries.addAll(_modification.getUpdatedConfigurationData().entrySet());
-        updatedEntries.removeAll(createdEntries);
-
-        val Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers = _modification.getRemovedConfigurationData();
-        for (Entry<InstanceIdentifier<? extends DataObject >, DataObject> entry : createdEntries) {
-            add(entry.key,entry.value);
-        }
-        for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
-                val originalFlow = _modification.originalConfigurationData.get(entry.key);
-                val updatedFlow = entry.value
-                update(entry.key, originalFlow ,updatedFlow);
-        }
-
-        for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
-            val removeValue = _modification.getOriginalConfigurationData.get(instanceId);
-                remove(instanceId,removeValue);
-        }
-    }
-    
-    def void remove(InstanceIdentifier<?> identifier, DataObject remove)
-    
-    def void update(InstanceIdentifier<?> identifier, DataObject original, DataObject update)
-    
-    def void add(InstanceIdentifier<?> identifier, DataObject add)
-    
-    def private rollbackRpcs() {
-        val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries = _modification.getCreatedConfigurationData().entrySet();
-
-        /*
-         * This little dance is because updatedEntries contains both created and modified entries
-         * The reason I created a new HashSet is because the collections we are returned are immutable.
-         */
-        val Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
-        updatedEntries.addAll(_modification.getUpdatedConfigurationData().entrySet());
-        updatedEntries.removeAll(createdEntries);
-
-        val Set<InstanceIdentifier<? >> removeEntriesInstanceIdentifiers = _modification.getRemovedConfigurationData();
-        for (Entry<InstanceIdentifier<?>, DataObject> entry : createdEntries) {
-            remove(entry.key,entry.value); // because we are rolling back, remove what we would have added.            
-        }
-        for (Entry<InstanceIdentifier<?>, DataObject> entry : updatedEntries) {
-            val originalFlow = _modification.originalConfigurationData.get(entry.key);
-            val updatedFlow = entry.value
-            update(entry.key, updatedFlow ,originalFlow);// because we are rolling back, replace the updated with the original
-        }
-
-        for (InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers ) {
-            val removeValue = _modification.getOriginalConfigurationData.get(instanceId);
-            add(instanceId,removeValue);// because we are rolling back, add what we would have removed.
-        }
-    }    
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java
new file mode 100644 (file)
index 0000000..929c489
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * 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.frm;
+
+import org.opendaylight.controller.frm.flow.FlowProvider;
+import org.opendaylight.controller.frm.group.GroupProvider;
+import org.opendaylight.controller.frm.meter.MeterProvider;
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FRMActivator extends AbstractBindingAwareProvider {
+
+    private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class);
+
+    private static FlowProvider flowProvider = new FlowProvider(); 
+    private static GroupProvider groupProvider = new GroupProvider();
+    private static MeterProvider meterProvider = new MeterProvider();
+    
+    @Override
+    public void onSessionInitiated(final ProviderContext session) {
+        DataProviderService flowSalService = session.<DataProviderService>getSALService(DataProviderService.class);
+        FRMActivator.flowProvider.setDataService(flowSalService);
+        SalFlowService rpcFlowSalService = session.<SalFlowService>getRpcService(SalFlowService.class);
+        FRMActivator.flowProvider.setSalFlowService(rpcFlowSalService);
+        FRMActivator.flowProvider.start();
+        DataProviderService groupSalService = session.<DataProviderService>getSALService(DataProviderService.class);
+        FRMActivator.groupProvider.setDataService(groupSalService);
+        SalGroupService rpcGroupSalService = session.<SalGroupService>getRpcService(SalGroupService.class);
+        FRMActivator.groupProvider.setSalGroupService(rpcGroupSalService);
+        FRMActivator.groupProvider.start();
+        DataProviderService meterSalService = session.<DataProviderService>getSALService(DataProviderService.class);
+        FRMActivator.meterProvider.setDataService(meterSalService);
+        SalMeterService rpcMeterSalService = session.<SalMeterService>getRpcService(SalMeterService.class);
+        FRMActivator.meterProvider.setSalMeterService(rpcMeterSalService);
+        FRMActivator.meterProvider.start();
+    }
+    
+    @Override
+    protected void stopImpl(final BundleContext context) {
+        try {
+            FRMActivator.flowProvider.close();
+            FRMActivator.groupProvider.close();
+            FRMActivator.meterProvider.close();
+        } catch (Throwable e) {
+            LOG.error("Unexpected error by stopping FRMActivator", e);
+            throw new RuntimeException(e);
+        }
+    }
+  }
\ No newline at end of file
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.xtend
deleted file mode 100644 (file)
index 8ec9d79..0000000
+++ /dev/null
@@ -1,47 +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.frm
-
-import org.opendaylight.controller.frm.flow.FlowProvider
-import org.opendaylight.controller.frm.group.GroupProvider
-import org.opendaylight.controller.frm.meter.MeterProvider
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.osgi.framework.BundleContext
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-
-class FRMActivator extends AbstractBindingAwareProvider {
-
-    static var FlowProvider provider = new FlowProvider();
-    static var GroupProvider groupProvider = new GroupProvider();
-    static var MeterProvider meterProvider = new MeterProvider();
-
-    override onSessionInitiated(ProviderContext session) {
-        provider.dataService = session.getSALService(DataProviderService)
-        provider.salFlowService = session.getRpcService(SalFlowService);
-        provider.start();
-        
-        groupProvider.dataService = session.getSALService(DataProviderService)
-        groupProvider.salGroupService = session.getRpcService(SalGroupService)
-        groupProvider.start();
-        
-        meterProvider.dataService = session.getSALService(DataProviderService)
-        meterProvider.salMeterService = session.getRpcService(SalMeterService)
-        meterProvider.start();
-    }
-
-    override protected stopImpl(BundleContext context) {
-        provider.close();
-        groupProvider.close();
-        meterProvider.close();
-    }
-
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java
new file mode 100644 (file)
index 0000000..df086c7
--- /dev/null
@@ -0,0 +1,120 @@
+/**
+ * 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.frm.flow;
+
+import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class FlowChangeListener extends AbstractChangeListener {
+
+    private final static Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class);
+
+    private final SalFlowService salFlowService;
+
+    public SalFlowService getSalFlowService() {
+        return this.salFlowService;
+    }
+    
+    public FlowChangeListener(final SalFlowService manager) {
+        this.salFlowService = manager;
+    }
+
+    @Override
+    protected void validate() throws IllegalStateException {
+        FlowTransactionValidator.validate(this);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
+        if ((removeDataObj instanceof Flow)) {
+            
+            final Flow flow = ((Flow) removeDataObj);
+            final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow);
+            
+            builder.setFlowRef(new FlowRef(identifier));
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setFlowTable(new FlowTableRef(tableInstanceId));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            this.salFlowService.removeFlow((RemoveFlowInput) builder.build());
+            LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj});
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
+        if (original instanceof Flow && update instanceof Flow) {
+            
+            final Flow originalFlow = ((Flow) original);
+            final Flow updatedFlow = ((Flow) update);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node>firstIdentifierOf(Node.class);
+            final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder();
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setFlowRef(new FlowRef(identifier));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            
+            builder.setUpdatedFlow((UpdatedFlow) (new UpdatedFlowBuilder(updatedFlow)).build());
+            builder.setOriginalFlow((OriginalFlow) (new OriginalFlowBuilder(originalFlow)).build());
+            
+            this.salFlowService.updateFlow((UpdateFlowInput) builder.build());
+            LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update});
+      }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
+        if ((addDataObj instanceof Flow)) {
+            
+            final Flow flow = ((Flow) addDataObj);
+            final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setFlowRef(new FlowRef(identifier));
+            builder.setFlowTable(new FlowTableRef(tableInstanceId));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            this.salFlowService.addFlow((AddFlowInput) builder.build());
+            LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj});
+        }
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowCommitHandler.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowCommitHandler.xtend
deleted file mode 100644 (file)
index 188bfcd..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.frm.flow
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-
-class FlowCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-       
-    @Property
-    val SalFlowService salFlowService;
-    
-    new(SalFlowService manager) {
-        _salFlowService = manager;
-    }
-    
-    override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
-        return new FlowTransaction(modification,salFlowService);
-    }
-    
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java
new file mode 100644 (file)
index 0000000..afdd628
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * 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.frm.flow;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowProvider implements AutoCloseable {
+
+    private final static Logger LOG = LoggerFactory.getLogger(FlowProvider.class);
+
+    private SalFlowService salFlowService;
+    private DataProviderService dataService;
+
+    /* DataChangeListener */
+    private FlowChangeListener flowDataChangeListener;
+    ListenerRegistration<DataChangeListener> flowDataChangeListenerRegistration;
+
+    public void start() {
+        /* Build Path */
+        InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
+        InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
+        InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
+        InstanceIdentifierBuilder<Table> tableChild = augmentFlowCapNode.<Table> child(Table.class);
+        InstanceIdentifierBuilder<Flow> flowChild = tableChild.<Flow> child(Flow.class);
+        final InstanceIdentifier<? extends DataObject> flowDataObjectPath = flowChild.toInstance();
+        
+        /* DataChangeListener registration */
+        this.flowDataChangeListener = new FlowChangeListener(this.salFlowService);
+        this.flowDataChangeListenerRegistration = this.dataService.registerDataChangeListener(flowDataObjectPath, flowDataChangeListener);
+        LOG.info("Flow Config Provider started.");
+    }
+
+    protected DataModificationTransaction startChange() {
+        return this.dataService.beginTransaction();
+    }
+
+    @Override
+    public void close() throws Exception {
+        if(flowDataChangeListenerRegistration != null){
+            flowDataChangeListenerRegistration.close();
+        }
+    }
+
+    public void setDataService(final DataProviderService dataService) {
+        this.dataService = dataService;
+    }
+
+    public void setSalFlowService(final SalFlowService salFlowService) {
+        this.salFlowService = salFlowService;
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.xtend
deleted file mode 100644 (file)
index d2ed541..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.frm.flow
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-class FlowProvider implements AutoCloseable {
-    
-    @Property
-    DataProviderService dataService;
-    
-    @Property
-    SalFlowService salFlowService;
-    
-    FlowCommitHandler commitHandler
-
-    Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-    
-    static val LOG = LoggerFactory.getLogger(FlowProvider);
-    
-    def void start() {
-        commitHandler = new FlowCommitHandler(salFlowService)
-        val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Nodes)
-            .child(Node)
-            .augmentation(FlowCapableNode)
-            .child(Table)
-            .child(Flow)
-            .toInstance();
-        commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
-        LOG.info("Flow Config Provider started.");
-    }
-
-    protected def startChange() {
-        return dataService.beginTransaction;
-    }
-    
-    override close() throws Exception {
-        throw new UnsupportedOperationException("TODO: auto-generated method stub")
-    }
-    
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransaction.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransaction.xtend
deleted file mode 100644 (file)
index 26846ad..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.frm.flow
-
-import org.opendaylight.controller.frm.AbstractTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri
-
-class FlowTransaction extends AbstractTransaction {
-    
-    @Property
-    val SalFlowService salFlowService;   
-    
-    
-    new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,SalFlowService salFlowService) {
-        super(modification)        
-        _salFlowService = salFlowService;
-    }
-    
-    override remove(InstanceIdentifier<?> instanceId, DataObject obj) {
-        if(obj instanceof Flow) {
-            val flow = (obj as Flow)
-            val tableInstanceId = instanceId.firstIdentifierOf(Table);
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new RemoveFlowInputBuilder(flow);
-            builder.setFlowRef(new FlowRef(instanceId));            
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setFlowTable(new FlowTableRef(tableInstanceId));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            _salFlowService.removeFlow(builder.build());            
-        }
-    }
-    
-    override update(InstanceIdentifier<?> instanceId, DataObject originalObj, DataObject updatedObj) {
-        if(originalObj instanceof Flow && updatedObj instanceof Flow) {
-            val originalFlow = (originalObj as Flow)
-            val updatedFlow = (updatedObj as Flow)
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new UpdateFlowInputBuilder();
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setFlowRef(new FlowRef(instanceId));
-            val ufb = new UpdatedFlowBuilder(updatedFlow);
-            builder.setUpdatedFlow((ufb.build()));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            val ofb = new OriginalFlowBuilder(originalFlow);
-            builder.setOriginalFlow(ofb.build());      
-            _salFlowService.updateFlow(builder.build());
-           
-        }
-    }
-    
-    override add(InstanceIdentifier<?> instanceId, DataObject obj) {
-        if(obj instanceof Flow) {
-            val flow = (obj as Flow)
-            val tableInstanceId = instanceId.firstIdentifierOf(Table);
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new AddFlowInputBuilder(flow);
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            builder.setFlowRef(new FlowRef(instanceId));
-            builder.setFlowTable(new FlowTableRef(tableInstanceId));
-            _salFlowService.addFlow(builder.build());            
-        }
-    }
-    
-    override validate() throws IllegalStateException {
-        FlowTransactionValidator.validate(this)
-    }  
-}
index 7c6f1ff1cb8afcf6fcd797194c99db160b8935e9..4ef93a55e9d515ebcc8e15312ae72108658d379b 100644 (file)
@@ -1,6 +1,6 @@
-/*
+/**
  * 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
@@ -9,8 +9,7 @@ package org.opendaylight.controller.frm.flow;
 
 public class FlowTransactionValidator {
 
-    public static void validate(FlowTransaction transaction) throws IllegalStateException {
+    public static void validate(FlowChangeListener transaction) throws IllegalStateException {
         // NOOP
     }
-
 }
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java
new file mode 100644 (file)
index 0000000..1260f0e
--- /dev/null
@@ -0,0 +1,113 @@
+/**
+ * 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.frm.group;
+
+import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class GroupChangeListener extends AbstractChangeListener {
+
+    private final static Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class);
+
+    private final SalGroupService salGroupService;
+
+    public SalGroupService getSalGroupService() {
+        return this.salGroupService;
+    }
+    
+    public GroupChangeListener(final SalGroupService manager) {
+        this.salGroupService = manager;
+    }
+
+    @Override
+    protected void validate() throws IllegalStateException {
+        GroupTransactionValidator.validate(this);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
+        if ((removeDataObj instanceof Group)) {
+            
+            final Group group = ((Group) removeDataObj);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setGroupRef(new GroupRef(identifier));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            this.salGroupService.removeGroup((RemoveGroupInput) builder.build());
+            LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj});
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
+        if (original instanceof Group && update instanceof Group) {
+            
+            final Group originalGroup = ((Group) original);
+            final Group updatedGroup = ((Group) update);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder();
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setGroupRef(new GroupRef(identifier));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            
+            builder.setUpdatedGroup((UpdatedGroup) (new UpdatedGroupBuilder(updatedGroup)).build());
+            builder.setOriginalGroup((OriginalGroup) (new OriginalGroupBuilder(originalGroup)).build());
+            
+            this.salGroupService.updateGroup((UpdateGroupInput) builder.build());
+            LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update});
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
+        if ((addDataObj instanceof Group)) {
+            final Group group = ((Group) addDataObj);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final AddGroupInputBuilder builder = new AddGroupInputBuilder(group);
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setGroupRef(new GroupRef(identifier));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            this.salGroupService.addGroup((AddGroupInput) builder.build());
+            LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj});
+        }
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupCommitHandler.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupCommitHandler.xtend
deleted file mode 100644 (file)
index b6d3851..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.frm.group
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-
-class GroupCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-       
-    @Property
-    val SalGroupService groupService;
-    
-    new(SalGroupService groupService) {
-        _groupService = groupService;
-    }
-    
-    override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
-        return new GroupTransaction(modification,groupService);
-    }
-    
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java
new file mode 100644 (file)
index 0000000..14b1b6f
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.frm.group;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GroupProvider implements AutoCloseable {
+
+    private final static Logger LOG = LoggerFactory.getLogger(GroupProvider.class);
+
+    private SalGroupService salGroupService;
+    private DataProviderService dataService;
+
+    /* DataChangeListener */
+    private GroupChangeListener groupDataChangeListener;
+    ListenerRegistration<DataChangeListener> groupDataChangeListenerRegistration;
+
+    public void start() {
+        /* Build Path */
+        InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
+        InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
+        InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
+        InstanceIdentifierBuilder<Group> groupChild = augmentFlowCapNode.<Group> child(Group.class);
+        final InstanceIdentifier<? extends DataObject> groupDataObjectPath = groupChild.toInstance();
+
+        /* DataChangeListener registration */
+        this.groupDataChangeListener = new GroupChangeListener(this.salGroupService);
+        this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(groupDataObjectPath, groupDataChangeListener);
+        LOG.info("Group Config Provider started.");
+    }
+    
+    protected DataModificationTransaction startChange() {
+        return this.dataService.beginTransaction();
+    }
+    
+    public void close() throws Exception {
+        if(groupDataChangeListenerRegistration != null){
+            groupDataChangeListenerRegistration.close();
+        }
+    }
+
+    public void setDataService(final DataProviderService dataService) {
+        this.dataService = dataService;
+    }
+
+    public void setSalGroupService(final SalGroupService salGroupService) {
+        this.salGroupService = salGroupService;
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.xtend
deleted file mode 100644 (file)
index 4ded8b6..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.frm.group
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-class GroupProvider implements AutoCloseable {
-    
-    @Property
-    DataProviderService dataService;
-    
-    @Property
-    SalGroupService salGroupService;
-    
-    GroupCommitHandler commitHandler
-
-    Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-    
-    static val LOG = LoggerFactory.getLogger(GroupProvider);
-    
-    def void start() {
-        commitHandler = new GroupCommitHandler(salGroupService)
-        val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Nodes)
-            .child(Node)
-            .augmentation(FlowCapableNode)
-            .child(Group)
-            .toInstance();
-        commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
-        LOG.info("Group Config Provider started.");
-    }
-
-    protected def startChange() {
-        return dataService.beginTransaction;
-    }
-    
-    override close() throws Exception {
-        throw new UnsupportedOperationException("TODO: auto-generated method stub")
-    }
-    
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransaction.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransaction.xtend
deleted file mode 100644 (file)
index e8d9982..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.frm.group
-
-import org.opendaylight.controller.frm.AbstractTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri
-
-class GroupTransaction extends AbstractTransaction {
-    
-    @Property
-    val SalGroupService groupService;
-        
-    new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,SalGroupService groupService) {
-        super(modification)        
-        _groupService = groupService;
-    }
-    
-    override remove(InstanceIdentifier<?> instanceId, DataObject obj) {
-        if(obj instanceof Group) {
-            val group = (obj as Group)
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new RemoveGroupInputBuilder(group);
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            builder.setGroupRef(new GroupRef(instanceId));
-            _groupService.removeGroup(builder.build());            
-        }
-    }
-    
-    override update(InstanceIdentifier<?> instanceId, DataObject originalObj, DataObject updatedObj) {
-        if(originalObj instanceof Group && updatedObj instanceof Group) {
-            val originalGroup = (originalObj as Group)
-            val updatedGroup = (updatedObj as Group)
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new UpdateGroupInputBuilder();
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setGroupRef(new GroupRef(instanceId));
-            val ufb = new UpdatedGroupBuilder(updatedGroup);
-            builder.setUpdatedGroup((ufb.build()));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            val ofb = new OriginalGroupBuilder(originalGroup);
-            builder.setOriginalGroup(ofb.build());      
-            _groupService.updateGroup(builder.build());
-           
-        }
-    }
-    
-    override add(InstanceIdentifier<?> instanceId, DataObject obj) {
-        if(obj instanceof Group) {
-            val group = (obj as Group)
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new AddGroupInputBuilder(group);
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setGroupRef(new GroupRef(instanceId));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            _groupService.addGroup(builder.build());            
-        }
-    }
-    
-    override validate() throws IllegalStateException {
-        GroupTransactionValidator.validate(this)
-    }  
-}
index 92baf7bdf0a022a7d1783e78d28bfffc4fc7a243..88eea0db343eb6c2725d7d6dc11580ceaddb50a1 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -9,8 +9,7 @@ package org.opendaylight.controller.frm.group;
 
 public class GroupTransactionValidator {
 
-    public static void validate(GroupTransaction transaction) throws IllegalStateException {
+    public static void validate(GroupChangeListener transaction) throws IllegalStateException {
         // NOOP
     }
-
 }
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java
new file mode 100644 (file)
index 0000000..839e556
--- /dev/null
@@ -0,0 +1,114 @@
+/**
+ * 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.frm.meter;
+
+import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class MeterChangeListener extends AbstractChangeListener {
+
+    private final static Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class);
+
+    private final SalMeterService salMeterService;
+
+    public SalMeterService getSalMeterService() {
+        return this.salMeterService;
+    }
+    
+    public MeterChangeListener(final SalMeterService manager) {
+        this.salMeterService = manager;
+    }
+
+    @Override
+    protected void validate() throws IllegalStateException {
+        MeterTransactionValidator.validate(this);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
+        if ((removeDataObj instanceof Meter)) {
+            
+            final Meter meter = ((Meter) removeDataObj);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter);
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setMeterRef(new MeterRef(identifier));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            this.salMeterService.removeMeter((RemoveMeterInput) builder.build());
+            LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj});
+        }
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
+        if (original instanceof Meter && update instanceof Meter) {
+            
+            final Meter originalMeter = ((Meter) original);
+            final Meter updatedMeter = ((Meter) update);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setMeterRef(new MeterRef(identifier));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            
+            builder.setUpdatedMeter((UpdatedMeter) (new UpdatedMeterBuilder(updatedMeter)).build());
+            builder.setOriginalMeter((OriginalMeter) (new OriginalMeterBuilder(originalMeter)).build());
+            
+            this.salMeterService.updateMeter((UpdateMeterInput) builder.build());
+            LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update});
+        }
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
+        if ((addDataObj instanceof Meter)) {
+            
+            final Meter meter = ((Meter) addDataObj);
+            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+            final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter);
+            
+            builder.setNode(new NodeRef(nodeInstanceId));
+            builder.setMeterRef(new MeterRef(identifier));
+            
+            Uri uri = new Uri(this.getTransactionId());
+            builder.setTransactionUri(uri);
+            this.salMeterService.addMeter((AddMeterInput) builder.build());
+            LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj});
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterCommitHandler.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterCommitHandler.xtend
deleted file mode 100644 (file)
index d5292f0..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.frm.meter
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-
-class FlowCommitHandler implements DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> {
-       
-    @Property
-    val SalMeterService salMeterService;
-    
-    new(SalMeterService manager) {
-        _salMeterService = manager;
-    }
-    
-    override requestCommit(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
-        return new MeterTransaction(modification,salMeterService);
-    }
-    
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java
new file mode 100644 (file)
index 0000000..620801f
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.frm.meter;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MeterProvider implements AutoCloseable {
+
+    private final static Logger LOG = LoggerFactory.getLogger(MeterProvider.class);
+
+    private DataProviderService dataService;
+    private SalMeterService salMeterService;
+
+    /* DataChangeListener */
+    private MeterChangeListener meterDataChangeListener;
+    ListenerRegistration<DataChangeListener> meterDataChangeListenerRegistration;
+
+    public void start() {
+        /* Build Path */
+        InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
+        InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
+        InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
+        InstanceIdentifierBuilder<Meter> meterChild = augmentFlowCapNode.<Meter> child(Meter.class);
+        final InstanceIdentifier<? extends DataObject> meterDataObjectPath = meterChild.toInstance();
+
+        /* DataChangeListener registration */
+        this.meterDataChangeListener = new MeterChangeListener(this.salMeterService);
+        this.meterDataChangeListenerRegistration = this.dataService.registerDataChangeListener(meterDataObjectPath, meterDataChangeListener);
+        LOG.info("Meter Config Provider started.");
+    }
+    
+    protected DataModificationTransaction startChange() {
+        return this.dataService.beginTransaction();
+    }
+
+    public void close() throws Exception {
+        if(meterDataChangeListenerRegistration != null){
+            meterDataChangeListenerRegistration.close();
+        }
+    }
+
+    public void setDataService(final DataProviderService dataService) {
+        this.dataService = dataService;
+    }
+
+    public void setSalMeterService(final SalMeterService salMeterService) {
+        this.salMeterService = salMeterService;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.xtend
deleted file mode 100644 (file)
index 323da57..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.frm.meter
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.slf4j.LoggerFactory
-
-class MeterProvider implements AutoCloseable {
-    
-    @Property
-    DataProviderService dataService;
-    
-    @Property
-    SalMeterService salMeterService;
-    
-    FlowCommitHandler commitHandler
-
-    Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>,DataObject>> commitHandlerRegistration;
-    
-    static val LOG = LoggerFactory.getLogger(MeterProvider);
-    
-    def void start() {
-        commitHandler = new FlowCommitHandler(salMeterService)
-        val InstanceIdentifier<? extends DataObject> path = InstanceIdentifier.builder(Nodes)
-            .child(Node)
-            .augmentation(FlowCapableNode)
-            .child(Meter)
-            .toInstance();
-        commitHandlerRegistration = dataService.registerCommitHandler(path,commitHandler);
-        LOG.info("Meter Config Provider started.");
-    }
-
-    protected def startChange() {
-        return dataService.beginTransaction;
-    }
-    
-    override close() throws Exception {
-        throw new UnsupportedOperationException("TODO: auto-generated method stub")
-    }
-    
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransaction.xtend b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransaction.xtend
deleted file mode 100644 (file)
index 491fa08..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.frm.meter
-
-import org.opendaylight.controller.frm.AbstractTransaction
-import org.opendaylight.controller.md.sal.common.api.data.DataModification
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri
-
-class MeterTransaction extends AbstractTransaction {
-    
-    @Property
-    val SalMeterService salMeterService;
-        
-    new(DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification,SalMeterService salMeterService) {
-        super(modification)    
-        _salMeterService = salMeterService;
-    }
-    
-    override remove(InstanceIdentifier<?> instanceId, DataObject obj) {
-        if(obj instanceof Meter) {
-            val meter = (obj as Meter)
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new RemoveMeterInputBuilder(meter);
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setMeterRef(new MeterRef(instanceId));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            _salMeterService.removeMeter(builder.build());            
-        }
-    }
-    
-    override update(InstanceIdentifier<?> instanceId, DataObject originalObj, DataObject updatedObj) {
-        if(originalObj instanceof Meter && updatedObj instanceof Meter) {
-            val originalMeter = (originalObj as Meter)
-            val updatedMeter = (updatedObj as Meter)
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new UpdateMeterInputBuilder();
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setMeterRef(new MeterRef(instanceId));
-            val ufb = new UpdatedMeterBuilder(updatedMeter);
-            builder.setUpdatedMeter((ufb.build()));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            val ofb = new OriginalMeterBuilder(originalMeter);
-            builder.setOriginalMeter(ofb.build());      
-            _salMeterService.updateMeter(builder.build());
-           
-        }
-    }
-    
-    override add(InstanceIdentifier<?> instanceId, DataObject obj) {
-        if(obj instanceof Meter) {
-            val meter = (obj as Meter)
-            val nodeInstanceId = instanceId.firstIdentifierOf(Node);
-            val builder = new AddMeterInputBuilder(meter);
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setMeterRef(new MeterRef(instanceId));
-            builder.setTransactionUri(new Uri(modification.getIdentifier() as String));
-            _salMeterService.addMeter(builder.build());            
-        }
-    }
-    
-    override validate() throws IllegalStateException {
-        MeterTransactionValidator.validate(this)
-    }  
-}
index b16739cc5b8f551dc25e10bfa24aed91ccfde46e..c8fba23b93601e4c3bde099e4e4a45221f1a2fdc 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -9,8 +9,7 @@ package org.opendaylight.controller.frm.meter;
 
 public class MeterTransactionValidator {
 
-    public static void validate(MeterTransaction transaction) throws IllegalStateException {
+    public static void validate(MeterChangeListener transaction) throws IllegalStateException {
         // NOOP
     }
-
 }
index 40a79033a7d163f3e5ecdd520cc5f938715131aa..1706996ce4a301ef4564ac765032c608c39bea68 100644 (file)
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.eclipse.xtend</groupId>
-      <artifactId>org.eclipse.xtend.lib</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-binding-api</artifactId>
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.eclipse.xtend</groupId>
-        <artifactId>xtend-maven-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
   <scm>
diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java
new file mode 100644 (file)
index 0000000..7e4190f
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.inventory.manager;
+
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FlowCapableInventoryProvider implements AutoCloseable {
+
+    private final static Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class);
+
+    private DataProviderService dataService;
+    private NotificationProviderService notificationService;
+    private Registration<NotificationListener> listenerRegistration;
+    private final NodeChangeCommiter changeCommiter = new NodeChangeCommiter(FlowCapableInventoryProvider.this);
+
+    public void start() {
+        this.listenerRegistration = this.notificationService.registerNotificationListener(this.changeCommiter);
+        LOG.info("Flow Capable Inventory Provider started.");
+    }
+
+    protected DataModificationTransaction startChange() {
+        DataProviderService _dataService = this.dataService;
+        return _dataService.beginTransaction();
+    }
+
+    @Override
+    public void close() {
+        try {
+            LOG.info("Flow Capable Inventory Provider stopped.");
+            if (this.listenerRegistration != null) {
+                this.listenerRegistration.close();
+            }
+        } catch (Exception e) {
+            String errMsg = "Error by stop Flow Capable Inventory Provider.";
+            LOG.error(errMsg, e);
+            throw new RuntimeException(errMsg, e);
+        }
+    }
+
+    public DataProviderService getDataService() {
+        return this.dataService;
+    }
+
+    public void setDataService(final DataProviderService dataService) {
+        this.dataService = dataService;
+    }
+
+    public NotificationProviderService getNotificationService() {
+        return this.notificationService;
+    }
+
+    public void setNotificationService(
+            final NotificationProviderService notificationService) {
+        this.notificationService = notificationService;
+    }
+}
diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend
deleted file mode 100644 (file)
index ec8da86..0000000
+++ /dev/null
@@ -1,63 +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.md.inventory.manager
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.yangtools.concepts.Registration
-import org.opendaylight.yangtools.yang.binding.NotificationListener
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
-import static extension org.opendaylight.controller.md.inventory.manager.InventoryMapping.*
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
-import org.slf4j.LoggerFactory
-
-class FlowCapableInventoryProvider implements AutoCloseable {
-
-
-    static val LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider);
-
-    @Property
-    DataProviderService dataService;
-
-    @Property
-    NotificationProviderService notificationService;
-    val NodeChangeCommiter changeCommiter = new NodeChangeCommiter(this);
-
-    Registration<NotificationListener> listenerRegistration
-
-    def void start() {
-        listenerRegistration = notificationService.registerNotificationListener(changeCommiter);
-        LOG.info("Flow Capable Inventory Provider started.");
-        
-    }
-
-    protected def startChange() {
-        return dataService.beginTransaction;
-    }
-
-    override close() {
-       LOG.info("Flow Capable Inventory Provider stopped.");
-        listenerRegistration?.close();
-    }
-    
-}
\ No newline at end of file
diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.java
new file mode 100644 (file)
index 0000000..6c06088
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * 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.inventory.manager;
+
+import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.osgi.framework.BundleContext;
+
+public class InventoryActivator extends AbstractBindingAwareProvider {
+
+    private static FlowCapableInventoryProvider provider = new FlowCapableInventoryProvider();
+
+    @Override
+    public void onSessionInitiated(final ProviderContext session) {
+        DataProviderService salDataService = session.<DataProviderService> getSALService(DataProviderService.class);
+        NotificationProviderService salNotifiService =
+                session.<NotificationProviderService> getSALService(NotificationProviderService.class);
+        InventoryActivator.provider.setDataService(salDataService);
+        InventoryActivator.provider.setNotificationService(salNotifiService);
+        InventoryActivator.provider.start();
+    }
+
+    @Override
+    protected void stopImpl(final BundleContext context) {
+        InventoryActivator.provider.close();
+    }
+}
diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.xtend b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryActivator.xtend
deleted file mode 100644 (file)
index 5d76924..0000000
+++ /dev/null
@@ -1,30 +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.md.inventory.manager
-
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
-import org.osgi.framework.BundleContext
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService
-
-class InventoryActivator extends AbstractBindingAwareProvider {
-
-    static var FlowCapableInventoryProvider provider = new FlowCapableInventoryProvider();
-
-    override onSessionInitiated(ProviderContext session) {
-        provider.dataService = session.getSALService(DataProviderService)
-        provider.notificationService = session.getSALService(NotificationProviderService)
-        provider.start();
-    }
-
-    override protected stopImpl(BundleContext context) {
-        provider.close();
-    }
-
-}
diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryMapping.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryMapping.java
new file mode 100644 (file)
index 0000000..928ae76
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * 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.inventory.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNodeConnector;
+
+public class InventoryMapping {
+
+    public static FlowCapableNodeConnector toInventoryAugment(final FlowNodeConnector updated) {
+        if ((updated instanceof FlowCapableNodeConnector)) {
+            return ((FlowCapableNodeConnector) updated);
+        }
+        final FlowCapableNodeConnectorBuilder builder = new FlowCapableNodeConnectorBuilder();
+        builder.setAdvertisedFeatures(updated.getAdvertisedFeatures());
+        builder.setConfiguration(updated.getConfiguration());
+        builder.setCurrentFeature(updated.getCurrentFeature());
+        builder.setCurrentSpeed(updated.getCurrentSpeed());
+        builder.setHardwareAddress(updated.getHardwareAddress());
+        builder.setMaximumSpeed(updated.getMaximumSpeed());
+        builder.setName(updated.getName());
+        builder.setPeerFeatures(updated.getPeerFeatures());
+        builder.setPortNumber(updated.getPortNumber());
+        builder.setState(updated.getState());
+        builder.setSupported(updated.getSupported());
+        return builder.build();
+    }
+
+    public static FlowCapableNode toInventoryAugment(final FlowNode source) {
+        if ((source instanceof FlowCapableNode)) {
+            return ((FlowCapableNode) source);
+        }
+        return (new FlowCapableNodeBuilder(source)).build();
+    }
+}
diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryMapping.xtend b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/InventoryMapping.xtend
deleted file mode 100644 (file)
index 6f1ef5e..0000000
+++ /dev/null
@@ -1,46 +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.md.inventory.manager
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNodeConnector
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowNode
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder
-
-class InventoryMapping {
-
-    static def FlowCapableNodeConnector toInventoryAugment(FlowNodeConnector updated) {
-        if (updated instanceof FlowCapableNodeConnector) {
-            return updated as FlowCapableNodeConnector;
-        }
-        val it = new FlowCapableNodeConnectorBuilder();
-        advertisedFeatures = updated.advertisedFeatures
-        configuration = updated.configuration
-        currentFeature = updated.currentFeature
-        currentSpeed = updated.currentSpeed
-        hardwareAddress = updated.hardwareAddress
-        maximumSpeed = updated.maximumSpeed
-        name = updated.name
-        peerFeatures = updated.peerFeatures
-        portNumber = updated.portNumber
-        state = updated.state
-        supported = updated.supported
-        return build();
-    }
-
-    static def FlowCapableNode toInventoryAugment(FlowNode source) {
-        if (source instanceof FlowCapableNode) {
-            return source as FlowCapableNode;
-        }
-        val it = new FlowCapableNodeBuilder(source);
-        return build();
-    }
-
-}
index ebb3de7dcae6d8380b1ad465a63e8900689740c1..03cdf973affae85e390c5b0cd07c445fb737a360 100644 (file)
@@ -20,7 +20,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeCon
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
@@ -39,8 +38,8 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Objects;
 
-@SuppressWarnings("all")
 public class NodeChangeCommiter implements OpendaylightInventoryListener {
+
     private final static Logger LOG = LoggerFactory.getLogger(NodeChangeCommiter.class);
 
     private final FlowCapableInventoryProvider manager;
@@ -75,7 +74,7 @@ public class NodeChangeCommiter implements OpendaylightInventoryListener {
         final NodeConnectorRef ref = connector.getNodeConnectorRef();
         final FlowCapableNodeConnectorUpdated flowConnector = connector
                 .getAugmentation(FlowCapableNodeConnectorUpdated.class);
-        final DataModificationTransaction it = this.getManager().startChange();
+        final DataModificationTransaction it = this.manager.startChange();
         final NodeConnectorBuilder data = new NodeConnectorBuilder(connector);
         NodeConnectorId id = connector.getId();
         NodeConnectorKey nodeConnectorKey = new NodeConnectorKey(id);
@@ -86,12 +85,9 @@ public class NodeChangeCommiter implements OpendaylightInventoryListener {
             data.addAugmentation(FlowCapableNodeConnector.class, augment);
         }
         InstanceIdentifier<? extends Object> value = ref.getValue();
-        String string = value.toString();
-        String plus = ("updating node connector : " + string);
-        NodeChangeCommiter.LOG.debug(plus);
-        InstanceIdentifier<? extends Object> value1 = ref.getValue();
+        NodeChangeCommiter.LOG.debug("updating node connector : {}.", value);
         NodeConnector build = data.build();
-        it.putOperationalData((value1), build);
+        it.putOperationalData((value), build);
         Future<RpcResult<TransactionStatus>> commitResult = it.commit();
         try {
             commitResult.get();
@@ -105,14 +101,9 @@ public class NodeChangeCommiter implements OpendaylightInventoryListener {
     public synchronized void onNodeRemoved(final NodeRemoved node) {
 
         final NodeRef ref = node.getNodeRef();
-        FlowCapableInventoryProvider manager = this.getManager();
-        final DataModificationTransaction it = manager.startChange();
-        InstanceIdentifier<? extends Object> value = ref.getValue();
-        String string = value.toString();
-        String plus = ("removing node : " + string);
-        NodeChangeCommiter.LOG.debug(plus);
-        InstanceIdentifier<? extends Object> value1 = ref.getValue();
-        it.removeOperationalData((value1));
+        final DataModificationTransaction it = this.manager.startChange();
+        NodeChangeCommiter.LOG.debug("removing node : {}", ref.getValue());
+        it.removeOperationalData((ref.getValue()));
         Future<RpcResult<TransactionStatus>> commitResult = it.commit();
         try {
             commitResult.get();
@@ -127,19 +118,15 @@ public class NodeChangeCommiter implements OpendaylightInventoryListener {
         final NodeRef ref = node.getNodeRef();
         final FlowCapableNodeUpdated flowNode = node
                 .<FlowCapableNodeUpdated> getAugmentation(FlowCapableNodeUpdated.class);
-        FlowCapableInventoryProvider manager = this.getManager();
-        final DataModificationTransaction it = manager.startChange();
-        NodeBuilder nodeBuilder = new NodeBuilder(node);
-        final NodeBuilder data = nodeBuilder;
-        NodeId id = node.getId();
-        NodeKey nodeKey = new NodeKey(id);
-        data.setKey(nodeKey);
+        final DataModificationTransaction it = this.manager.startChange();
+        final NodeBuilder nodeBuilder = new NodeBuilder(node);
+        nodeBuilder.setKey(new NodeKey(node.getId()));
         boolean equals = Objects.equal(flowNode, null);
         if (equals) {
             return;
         }
         final FlowCapableNode augment = InventoryMapping.toInventoryAugment(flowNode);
-        data.addAugmentation(FlowCapableNode.class, augment);
+        nodeBuilder.addAugmentation(FlowCapableNode.class, augment);
         InstanceIdentifier<? extends Object> value = ref.getValue();
         InstanceIdentifierBuilder<Node> builder = InstanceIdentifier.<Node> builder(((InstanceIdentifier<Node>) value));
         InstanceIdentifierBuilder<FlowCapableNode> augmentation = builder
index 8760a34c2350be11704ee4f88527ed13c989b92f..451edfdf78cb84c734590472507898b9a7b99ac2 100644 (file)
           <configuration>
             <lifecycleMappingMetadata>
               <pluginExecutions>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.opendaylight.yangtools</groupId>
-                    <artifactId>yang-maven-plugin</artifactId>
-                    <versionRange>[0,)</versionRange>
-                    <goals>
-                      <goal>generate-sources</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
                 <pluginExecution>
                   <pluginExecutionFilter>
                     <groupId>net.alchim31.maven</groupId>
index 6bd6e6aaf52294ed0ada1b2809995ea1b7877260..cc9c6ebaa6e18bb20ee9e9245a4d34b8321733e0 100644 (file)
@@ -82,7 +82,7 @@ public class AbstractForwardedTransaction<T extends AsyncTransaction<org.openday
                 try {
                     final DataObject dataObject = normalizedNode.isPresent() ? codec.toBinding(path,
                             normalizedNode.get()) : null;
-                    if(dataObject != null) {
+                    if (dataObject != null) {
                         updateCache(store, path, dataObject);
                     }
                     return Optional.fromNullable(dataObject);
@@ -109,6 +109,27 @@ public class AbstractForwardedTransaction<T extends AsyncTransaction<org.openday
                 .toNormalizedNode(path, data);
 
         org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey();
+        ensureParentsByMerge(writeTransaction, store, normalized.getKey(), path);
+        LOG.debug("Tx: {} : Putting data {}",getDelegate().getIdentifier(),normalized.getKey());
+        writeTransaction.put(store, normalized.getKey(), normalized.getValue());
+    }
+
+    protected void doMergeWithEnsureParents(final DOMDataReadWriteTransaction writeTransaction,
+            final LogicalDatastoreType store, final InstanceIdentifier<?> path, final DataObject data) {
+        invalidateCache(store, path);
+        final Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalized = codec
+                .toNormalizedNode(path, data);
+
+        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey();
+        ensureParentsByMerge(writeTransaction, store, normalized.getKey(), path);
+        LOG.debug("Tx: {} : Merge data {}",getDelegate().getIdentifier(),normalized.getKey());
+        writeTransaction.merge(store, normalized.getKey(), normalized.getValue());
+    }
+
+    private void ensureParentsByMerge(final DOMDataReadWriteTransaction writeTransaction,
+            final LogicalDatastoreType store,
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath,
+            final InstanceIdentifier<?> path) {
         List<PathArgument> currentArguments = new ArrayList<>();
         DataNormalizationOperation<?> currentOp = codec.getDataNormalizer().getRootOperation();
         Iterator<PathArgument> iterator = normalizedPath.getPath().iterator();
@@ -135,8 +156,6 @@ public class AbstractForwardedTransaction<T extends AsyncTransaction<org.openday
                 writeTransaction.merge(store, currentPath, currentOp.createDefault(currentArg));
             }
         }
-        //LOG .info("Tx: {} : Putting data {}",getDelegate().getIdentifier(),normalized.getKey());
-        writeTransaction.put(store, normalized.getKey(), normalized.getValue());
     }
 
     protected void doMerge(final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType store,
index 35ebe76499f51e6bb5b629c4cf42a944fe727ea8..6329637dd01cfdad2470345e4c8433a07fe62ebf 100644 (file)
@@ -7,28 +7,43 @@
  */
 package org.opendaylight.controller.md.sal.binding.impl;
 
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.util.AbstractMap.SimpleEntry;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map.Entry;
+import java.util.concurrent.Callable;
 
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
 
 public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
@@ -44,10 +59,15 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalized(
             final InstanceIdentifier<? extends DataObject> binding) {
-        final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath = bindingToLegacy.toDataDom(binding);
-        final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = legacyToNormalized.toNormalized(legacyPath);
-        LOG.trace("InstanceIdentifier Path {} Serialization: Legacy representation {}, Normalized representation: {}",binding,legacyPath,normalized);
-        return normalized;
+
+        // Used instance-identifier codec do not support serialization of last path
+        // argument if it is Augmentation (behaviour expected by old datastore)
+        // in this case, we explicitly check if last argument is augmentation
+        // to process it separately
+        if (isAugmentationIdentifier(binding)) {
+            return toNormalizedAugmented(binding);
+        }
+        return toNormalizedImpl(binding);
     }
 
     public Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
@@ -58,39 +78,85 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     public Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
             final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> binding) {
-        Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> legacyEntry = bindingToLegacy.toDataDom(binding);
-        Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalizedEntry = legacyToNormalized.toNormalized(legacyEntry);
-        LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}",binding,legacyEntry,normalizedEntry);
-        if(Augmentation.class.isAssignableFrom(binding.getKey().getTargetType())) {
-
-            for(DataContainerChild<? extends PathArgument, ?> child : ((DataContainerNode<?>) normalizedEntry.getValue()).getValue()) {
-               if(child instanceof AugmentationNode) {
-                   ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument>builder()
-                           .addAll(normalizedEntry.getKey().getPath())
-                           .add(child.getIdentifier())
-                           .build();
-                   org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(childArgs);
-                   return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(childPath,child);
-               }
+        Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> legacyEntry = bindingToLegacy
+                .toDataDom(binding);
+        Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>> normalizedEntry = legacyToNormalized
+                .toNormalized(legacyEntry);
+        LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}", binding,
+                legacyEntry, normalizedEntry);
+        if (Augmentation.class.isAssignableFrom(binding.getKey().getTargetType())) {
+
+            for (DataContainerChild<? extends PathArgument, ?> child : ((DataContainerNode<?>) normalizedEntry
+                    .getValue()).getValue()) {
+                if (child instanceof AugmentationNode) {
+                    ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument> builder()
+                            .addAll(normalizedEntry.getKey().getPath()).add(child.getIdentifier()).build();
+                    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
+                            childArgs);
+                    return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, NormalizedNode<?, ?>>(
+                            childPath, child);
+                }
             }
 
         }
         return normalizedEntry;
 
-
     }
 
     public InstanceIdentifier<? extends DataObject> toBinding(
             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
             throws DeserializationException {
 
+        PathArgument lastArgument = Iterables.getLast(normalized.getPath());
+        // Used instance-identifier codec do not support serialization of last path
+        // argument if it is AugmentationIdentifier (behaviour expected by old datastore)
+        // in this case, we explicitly check if last argument is augmentation
+        // to process it separately
+        if (lastArgument instanceof AugmentationIdentifier) {
+            return toBindingAugmented(normalized);
+        }
+        return toBindingImpl(normalized);
+    }
+
+    private InstanceIdentifier<? extends DataObject> toBindingAugmented(
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) throws DeserializationException {
+        InstanceIdentifier<? extends DataObject> potential = toBindingImpl(normalized);
+        // Shorthand check, if codec already supports deserialization
+        // of AugmentationIdentifier we will return
+        if(isAugmentationIdentifier(potential)) {
+            return potential;
+        }
+
+        AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPath());
+
+        // Here we employ small trick - Binding-aware Codec injects an pointer to augmentation class
+        // if child is referenced - so we will reference child and then shorten path.
+        for (QName child : lastArgument.getPossibleChildNames()) {
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
+                    ImmutableList.<PathArgument> builder()
+                    .addAll(normalized.getPath()).add(new NodeIdentifier(child)).build());
+            try {
+
+                InstanceIdentifier<? extends DataObject> potentialPath = shortenToLastAugment(toBindingImpl(childPath));
+                return potentialPath;
+            } catch (Exception e) {
+                LOG.trace("Unable to deserialize aug. child path for {}",childPath,e);
+            }
+        }
+        return toBindingImpl(normalized);
+    }
+
+    private InstanceIdentifier<? extends DataObject> toBindingImpl(
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized)
+            throws DeserializationException {
         org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath;
         try {
             legacyPath = legacyToNormalized.toLegacy(normalized);
         } catch (DataNormalizationException e) {
-            throw new IllegalStateException("Could not denormalize path.",e);
+            throw new IllegalStateException("Could not denormalize path.", e);
         }
-        LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",legacyPath,normalized);
+        LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",
+                legacyPath, normalized);
         return bindingToLegacy.fromDataDom(legacyPath);
     }
 
@@ -103,7 +169,19 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
             throws DeserializationException {
-        return bindingToLegacy.dataObjectFromDataDom(path, (CompositeNode) DataNormalizer.toLegacy(normalizedNode));
+        CompositeNode legacy = null;
+        if(isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) {
+            QName augIdentifier = BindingReflections.findQName(path.getTargetType());
+            ContainerNode virtualNode = Builders.containerBuilder() //
+                    .withNodeIdentifier(new NodeIdentifier(augIdentifier)) //
+                    .withChild((DataContainerChild<?, ?>) normalizedNode) //
+                    .build();
+            legacy = (CompositeNode) DataNormalizer.toLegacy(virtualNode);
+        } else {
+            legacy = (CompositeNode) DataNormalizer.toLegacy(normalizedNode);
+        }
+
+        return bindingToLegacy.dataObjectFromDataDom(path, legacy);
     }
 
     public DataNormalizer getDataNormalizer() {
@@ -123,4 +201,141 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
         legacyToNormalized = new DataNormalizer(arg0);
     }
 
+    private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalizedAugmented(
+            final InstanceIdentifier<?> augPath) {
+        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier processed = toNormalizedImpl(augPath);
+        // If used instance identifier codec added supports for deserialization
+        // of last AugmentationIdentifier we will just reuse it
+        if(isAugmentationIdentifier(processed)) {
+            return processed;
+        }
+        // Here we employ small trick - DataNormalizer injecst augmentation identifier if child is
+        // also part of the path (since using a child we can safely identify augmentation)
+        // so, we scan augmentation for children add it to path
+        // and use original algorithm, then shorten it to last augmentation
+        for (@SuppressWarnings("rawtypes") Class augChild : getAugmentationChildren(augPath.getTargetType())) {
+            @SuppressWarnings("unchecked")
+            InstanceIdentifier<?> childPath = augPath.child(augChild);
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = toNormalizedImpl(childPath);
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potentialDiscovered = shortenToLastAugmentation(normalized);
+            if (potentialDiscovered != null) {
+                return potentialDiscovered;
+            }
+        }
+        return processed;
+    }
+
+
+
+    private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier shortenToLastAugmentation(
+            final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) {
+        int position = 0;
+        int foundPosition = -1;
+        for (PathArgument arg : normalized.getPath()) {
+            position++;
+            if (arg instanceof AugmentationIdentifier) {
+                foundPosition = position;
+            }
+        }
+        if (foundPosition > 0) {
+            return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(normalized.getPath().subList(0,
+                    foundPosition));
+        }
+        return null;
+    }
+
+    private InstanceIdentifier<? extends DataObject> shortenToLastAugment(
+            final InstanceIdentifier<? extends DataObject> binding) {
+        int position = 0;
+        int foundPosition = -1;
+        for(org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
+            position++;
+            if (isAugmentation(arg.getType())) {
+                foundPosition = position;
+            }
+        }
+        return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition));
+    }
+
+
+
+    private org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toNormalizedImpl(
+            final InstanceIdentifier<? extends DataObject> binding) {
+        final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier legacyPath = bindingToLegacy
+                .toDataDom(binding);
+        final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = legacyToNormalized
+                .toNormalized(legacyPath);
+        return normalized;
+    }
+
+    @SuppressWarnings("unchecked")
+    private Iterable<Class<? extends DataObject>> getAugmentationChildren(final Class<?> targetType) {
+        List<Class<? extends DataObject>> ret = new LinkedList<>();
+        for (Method method : targetType.getMethods()) {
+            Class<?> entity = getYangModeledType(method);
+            if (entity != null) {
+                ret.add((Class<? extends DataObject>) entity);
+            }
+        }
+        return ret;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private Class<? extends DataObject> getYangModeledType(final Method method) {
+        if (method.getName().equals("getClass") || !method.getName().startsWith("get")
+                || method.getParameterTypes().length > 0) {
+            return null;
+        }
+
+        Class<?> returnType = method.getReturnType();
+        if (DataContainer.class.isAssignableFrom(returnType)) {
+            return (Class) returnType;
+        } else if (List.class.isAssignableFrom(returnType)) {
+            try {
+                return ClassLoaderUtils.withClassLoader(method.getDeclaringClass().getClassLoader(),
+                        new Callable<Class>() {
+
+                            @SuppressWarnings("rawtypes")
+                            @Override
+                            public Class call() throws Exception {
+                                Type listResult = ClassLoaderUtils.getFirstGenericParameter(method
+                                        .getGenericReturnType());
+                                if (listResult instanceof Class
+                                        && DataObject.class.isAssignableFrom((Class) listResult)) {
+                                    return (Class<?>) listResult;
+                                }
+                                return null;
+                            }
+
+                        });
+            } catch (Exception e) {
+                LOG.debug("Could not get YANG modeled entity for {}", method, e);
+                return null;
+            }
+
+        }
+        return null;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private static InstanceIdentifier<?> toWildcarded(final InstanceIdentifier<?> orig) {
+        List<org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument> wildArgs = new LinkedList<>();
+        for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : orig.getPathArguments()) {
+            wildArgs.add(new Item(arg.getType()));
+        }
+        return InstanceIdentifier.create(wildArgs);
+    }
+
+
+    private static boolean isAugmentation(final Class<? extends DataObject> type) {
+        return Augmentation.class.isAssignableFrom(type);
+    }
+
+    private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> path) {
+        return Augmentation.class.isAssignableFrom(path.getTargetType());
+    }
+
+    private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier processed) {
+        return Iterables.getLast(processed.getPath()) instanceof AugmentationIdentifier;
+    }
 }
index ab0dc6e24fb91c96ebf6e40aaa2b6251489a3c2b..ddc79ae075e7551cfd369a81795da0f040b427e6 100644 (file)
@@ -195,6 +195,7 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
     private class ForwardedBackwardsCompatibleTransacion extends
             AbstractForwardedTransaction<DOMDataReadWriteTransaction> implements DataModificationTransaction {
 
+        private final ListenerRegistry<DataTransactionListener> listeners = ListenerRegistry.create();
         private final Map<InstanceIdentifier<? extends DataObject>, DataObject> updated = new HashMap<>();
         private final Map<InstanceIdentifier<? extends DataObject>, DataObject> created = new HashMap<>();
         private final Set<InstanceIdentifier<? extends DataObject>> removed = new HashSet<>();
@@ -218,13 +219,17 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
 
         @Override
         public void putOperationalData(final InstanceIdentifier<? extends DataObject> path, final DataObject data) {
-            posponedRemovedOperational.remove(path);
-            doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data);
+            boolean previouslyRemoved = posponedRemovedOperational.remove(path);
+            if(previouslyRemoved) {
+                doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data);
+            } else {
+                doMergeWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data);
+            }
         }
 
         @Override
         public void putConfigurationData(final InstanceIdentifier<? extends DataObject> path, final DataObject data) {
-            posponedRemovedConfiguration.remove(path);
+            boolean previouslyRemoved = posponedRemovedConfiguration.remove(path);
             DataObject originalObj = readConfigurationData(path);
             if (originalObj != null) {
                 original.put(path, originalObj);
@@ -233,7 +238,11 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
                 created.put(path, data);
             }
             updated.put(path, data);
-            doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data);
+            if(previouslyRemoved) {
+                doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data);
+            } else {
+                doMergeWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data);
+            }
         }
 
         @Override
@@ -314,6 +323,14 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
         private void changeStatus(final TransactionStatus status) {
             LOG.trace("Transaction {} changed status to {}", getIdentifier(), status);
             this.status = status;
+
+            for(ListenerRegistration<DataTransactionListener> listener : listeners) {
+                try {
+                    listener.getInstance().onStatusUpdated(this, status);
+                } catch (Exception e) {
+                    LOG.error("Error during invoking transaction listener {}",listener.getInstance(),e);
+                }
+            }
         }
 
         @Override
@@ -327,10 +344,10 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
                 doDelete(getDelegate(), LogicalDatastoreType.OPERATIONAL, path);
             }
 
-            final ListenableFuture<RpcResult<TransactionStatus>> f = ForwardedBackwardsCompatibleDataBroker.this.commit(this);
-
             changeStatus(TransactionStatus.SUBMITED);
 
+            final ListenableFuture<RpcResult<TransactionStatus>> f = ForwardedBackwardsCompatibleDataBroker.this.commit(this);
+
             Futures.addCallback(f, new FutureCallback<RpcResult<TransactionStatus>>() {
                 @Override
                 public void onSuccess(final RpcResult<TransactionStatus> result) {
@@ -349,7 +366,7 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
 
         @Override
         public ListenerRegistration<DataTransactionListener> registerListener(final DataTransactionListener listener) {
-            throw new UnsupportedOperationException();
+            return listeners.register(listener);
         }
 
     }
index ac26445bf408677b6e397c9fbb77bcf4fcaa19de..4141bba2d44ec1ec13502c984efc36e282f4f912 100644 (file)
@@ -33,6 +33,8 @@ public class SingletonHolder {
 
     public static final int CORE_NOTIFICATION_THREADS = 4;
     public static final int MAX_NOTIFICATION_THREADS = 32;
+    // block caller thread after MAX_NOTIFICATION_THREADS + MAX_NOTIFICATION_QUEUE_SIZE pending notifications
+    public static final int MAX_NOTIFICATION_QUEUE_SIZE = 10;
     public static final int NOTIFICATION_THREAD_LIFE = 15;
 
     private static ListeningExecutorService NOTIFICATION_EXECUTOR = null;
@@ -47,19 +49,15 @@ public class SingletonHolder {
     public static synchronized final ListeningExecutorService getDefaultNotificationExecutor() {
 
         if (NOTIFICATION_EXECUTOR == null) {
-            // Overriding the queue since we need an unbounded queue
-            // and threadpoolexecutor would not create new threads if the queue is not full
-            BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>() {
+            // Overriding the queue:
+            // ThreadPoolExecutor would not create new threads if the queue is not full, thus adding
+            // occurs in RejectedExecutionHandler.
+            // This impl saturates threadpool first, then queue. When both are full caller will get blocked.
+            BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(MAX_NOTIFICATION_QUEUE_SIZE) {
                 @Override
                 public boolean offer(Runnable r) {
-                    if (size() <= 1) {
-                        // if the queue is empty (or has just 1), no need to rampup the threads
-                        return super.offer(r);
-                    } else {
-                        // if the queue is not empty, force the queue to return false.
-                        // threadpoolexecutor will spawn a new thread if the queue.offer returns false.
-                        return false;
-                    }
+                    // ThreadPoolExecutor will spawn a new thread after core size is reached only if the queue.offer returns false.
+                    return false;
                 }
             };
 
@@ -74,7 +72,8 @@ public class SingletonHolder {
                             try {
                                 executor.getQueue().put(r);
                             } catch (InterruptedException e) {
-                                e.printStackTrace();
+                                Thread.currentThread().interrupt();// set interrupt flag after clearing
+                                throw new IllegalStateException(e);
                             }
                         }
                     });
diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolderTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolderTest.java
new file mode 100644 (file)
index 0000000..0e4c5cc
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.sal.binding.codegen.impl;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import java.lang.reflect.Field;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Ignore
+public class SingletonHolderTest {
+    private static final Logger logger = LoggerFactory.getLogger(SingletonHolderTest.class);
+
+    @Test
+    public void testNotificationExecutor() throws Exception {
+        ListeningExecutorService executor = SingletonHolder.getDefaultNotificationExecutor();
+        ThreadPoolExecutor tpExecutor = (ThreadPoolExecutor) setAccessible(executor.getClass().getDeclaredField("delegate")).get(executor);
+        BlockingQueue<Runnable> queue = tpExecutor.getQueue();
+
+        for (int idx = 0; idx < 100; idx++) {
+            final int idx2 = idx;
+            logger.info("Adding {}\t{}\t{}", idx, queue.size(), tpExecutor.getActiveCount());
+            executor.execute(new Runnable() {
+
+                @Override
+                public void run() {
+                    logger.info("in  {}", idx2);
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    logger.info("out {}", idx2);
+                }
+            });
+        }
+        executor.shutdown();
+        executor.awaitTermination(10, TimeUnit.SECONDS);
+    }
+
+    private static Field setAccessible(Field field) {
+        field.setAccessible(true);
+        return field;
+    }
+}
index 21fa207d781a8cd74a16b49b1f7dc72d77e89daf..d1354f897fdcd45133c3ae17c5045a1ddf046095 100644 (file)
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-binding</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-binding-broker-impl</artifactId>
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
-    <dependency>
-    <groupId>org.opendaylight.yangtools</groupId>
-    <artifactId>yang-binding</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller.model</groupId>
       <artifactId>model-flow-management</artifactId>
   </dependencies>
   <build>
     <plugins>
-    <plugin>
-        <groupId>org.opendaylight.yangtools</groupId>
-        <artifactId>yang-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <goals>
-              <goal>generate-sources</goal>
-            </goals>
-            <configuration>
-              <codeGenerators>
-                <generator>
-                  <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
-                  <outputBaseDir>${salGeneratorPath}</outputBaseDir>
-                </generator>
-              </codeGenerators>
-              <inspectDependencies>true</inspectDependencies>
-            </configuration>
-          </execution>
-        </executions>
-    </plugin>
       <plugin>
         <groupId>org.jacoco</groupId>
         <artifactId>jacoco-maven-plugin</artifactId>
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>generate-sources</goal>
+            </goals>
+            <configuration>
+              <codeGenerators>
+                <generator>
+                  <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                  <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                </generator>
+              </codeGenerators>
+              <inspectDependencies>true</inspectDependencies>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   <scm>
diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentListenAugmentTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentListenAugmentTest.java
new file mode 100644 (file)
index 0000000..cb31885
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.sal.binding.test.bugfix;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+public class WriteParentListenAugmentTest extends AbstractDataServiceTest {
+
+    private static final String NODE_ID = "node:1";
+
+    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+            .child(Node.class, NODE_KEY).toInstance();
+
+    private static final InstanceIdentifier<FlowCapableNode> AUGMENT_WILDCARDED_PATH = InstanceIdentifier
+            .builder(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class).toInstance();
+
+    private static final InstanceIdentifier<FlowCapableNode> AUGMENT_NODE_PATH = InstanceIdentifier
+            .builder(Nodes.class).child(Node.class, NODE_KEY).augmentation(FlowCapableNode.class).toInstance();
+
+    @Test
+    public void writeNodeListenAugment() throws Exception {
+
+        final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> event = SettableFuture.create();
+
+        ListenerRegistration<DataChangeListener> dclRegistration = baDataService.registerDataChangeListener(
+                AUGMENT_WILDCARDED_PATH, new DataChangeListener() {
+
+                    @Override
+                    public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+                        event.set(change);
+                    }
+                });
+
+        DataModificationTransaction modification = baDataService.beginTransaction();
+
+        Node node = new NodeBuilder() //
+                .setKey(NODE_KEY) //
+                .addAugmentation(FlowCapableNode.class, flowCapableNode("one")).build();
+        modification.putOperationalData(NODE_INSTANCE_ID_BA, node);
+        modification.commit().get();
+
+        DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedEvent = event.get(1000, TimeUnit.MILLISECONDS);
+        assertTrue(receivedEvent.getCreatedOperationalData().containsKey(AUGMENT_NODE_PATH));
+
+        dclRegistration.close();
+
+        DataModificationTransaction mod2 = baDataService.beginTransaction();
+        mod2.putOperationalData(AUGMENT_NODE_PATH, flowCapableNode("two"));
+        mod2.commit().get();
+
+        FlowCapableNode readedAug = (FlowCapableNode) baDataService.readOperationalData(AUGMENT_NODE_PATH);
+        assertEquals("two", readedAug.getDescription());
+
+    }
+
+    private FlowCapableNode flowCapableNode(final String description) {
+        return new FlowCapableNodeBuilder() //
+                .setDescription(description) //
+                .build();
+    }
+}
\ No newline at end of file
index a91799d45823a2e2a6c8f90e69cd0931df18584d..19235d2ddfe56bac11b05cfe2bc9d36fee271bde 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 public final class ImmutableDataChangeEvent<P extends Path<P>, D> implements DataChangeEvent<P,D> {
 
@@ -127,6 +128,8 @@ public final class ImmutableDataChangeEvent<P extends Path<P>, D> implements Dat
             originalOperational.putAll(Maps.filterKeys(data.getOriginalOperationalData(), keyFilter));
             createdOperational.putAll(Maps.filterKeys(data.getCreatedOperationalData(), keyFilter));
             createdConfiguration.putAll(Maps.filterKeys(data.getCreatedConfigurationData(), keyFilter));
+            removedOperational.addAll(Sets.filter(data.getRemovedOperationalData(), keyFilter));
+            removedConfiguration.addAll(Sets.filter(data.getRemovedConfigurationData(), keyFilter));
             return this;
         }
 
index c62c27dea8908f8043b05561685b7db5ac555adc..e74ba958915d2809b6cac4dc927ea329840652fa 100644 (file)
@@ -394,7 +394,8 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
 
         Builder eventBuilder = builder(potentialScope) //
                 .setBefore(beforeCont) //
-                .setAfter(afterCont);
+                .setAfter(afterCont)
+                .addUpdated(path, beforeCont, afterCont);
         for (DOMImmutableDataChangeEvent childChange : childChanges) {
             eventBuilder.merge(childChange);
         }
@@ -447,27 +448,34 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
             final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
             final SimpleEventFactory eventFactory) {
 
-        DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
-
-        if (!listeners.isEmpty()) {
+        final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
+        DOMImmutableDataChangeEvent propagateEvent = event;
             // We have listeners for this node or it's children, so we will try
             // to do additional processing
-            if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
-                // Node has children, so we will try to resolve it's children
-                // changes.
-                @SuppressWarnings("unchecked")
-                NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
-                for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
-                    PathArgument childId = child.getIdentifier();
-                    Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
-                    if (!childListeners.isEmpty()) {
-                        resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory);
-                    }
-                }
+        if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
+            Builder eventBuilder = builder(DataChangeScope.BASE);
+            eventBuilder.merge(event);
+            eventBuilder.setBefore(event.getOriginalSubtree());
+            eventBuilder.setAfter(event.getUpdatedSubtree());
+
+            // Node has children, so we will try to resolve it's children
+            // changes.
+            @SuppressWarnings("unchecked")
+            NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
+            for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
+                PathArgument childId = child.getIdentifier();
+                Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
+                eventBuilder.merge(resolveSameEventRecursivelly(append(path, childId), childListeners, child, eventFactory));
             }
+            propagateEvent = eventBuilder.build();
+        } else {
+            // We do not dispatch leaf events since Binding Aware components do not support them.
+            propagateEvent = builder(DataChangeScope.BASE).build();
+        }
+        if (!listeners.isEmpty()) {
             addPartialTask(listeners, event);
         }
-        return event;
+        return propagateEvent;
     }
 
     private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
@@ -476,7 +484,7 @@ public class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeList
 
         Builder one = builder(DataChangeScope.ONE).setBefore(before.getData()).setAfter(after.getData());
 
-        Builder subtree = builder(DataChangeScope.SUBTREE);
+        Builder subtree = builder(DataChangeScope.SUBTREE).setBefore(before.getData()).setAfter(after.getData());
 
         for (NodeModification childMod : modification.getModifications()) {
             PathArgument childId = childMod.getIdentifier();
index a5c9b7983a92f93a9a2e2049688e0d33eaed1c8b..7ea4d4e09fc1590557b339b65ce78a8fb54f25c6 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.controller.md.sal.dom.store.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -36,8 +37,10 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableCo
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -70,7 +73,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
         } else if (schemaNode instanceof ChoiceNode) {
             return new ChoiceModificationStrategy((ChoiceNode) schemaNode);
         } else if (schemaNode instanceof LeafListSchemaNode) {
-            return new LeafSetEntryModificationStrategy((LeafListSchemaNode) schemaNode);
+            return fromLeafListSchemaNode((LeafListSchemaNode) schemaNode);
         } else if (schemaNode instanceof LeafSchemaNode) {
             return new LeafModificationStrategy((LeafSchemaNode) schemaNode);
         }
@@ -89,6 +92,15 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
         return new UnorderedMapModificationStrategy(schemaNode);
     }
 
+    private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) {
+        if(schemaNode.isUserOrdered()) {
+            return new OrderedLeafSetModificationStrategy(schemaNode);
+        } else {
+            return new UnorderedLeafSetModificationStrategy(schemaNode);
+        }
+    }
+
+
     public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
             final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
         AugmentationSchema augSchema = null;
@@ -504,7 +516,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
             DataNodeContainerModificationStrategy<AugmentationSchema> {
 
         protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
-            super(schema, AugmentationNode.class);
+            super(createAugmentProxy(schema,resolved), AugmentationNode.class);
             // FIXME: Use resolved children instead of unresolved.
 
         }
@@ -563,12 +575,12 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
     }
 
-    public static class LeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+    public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
 
         private final Optional<ModificationApplyOperation> entryStrategy;
 
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        protected LeafSetModificationStrategy(final LeafListSchemaNode schema) {
+        protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
             super((Class) LeafSetNode.class);
             entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
         }
@@ -589,6 +601,32 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
     }
 
+    public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+        private final Optional<ModificationApplyOperation> entryStrategy;
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
+            super((Class) LeafSetNode.class);
+            entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) {
+            return ImmutableOrderedLeafSetNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+            if (identifier instanceof NodeWithValue) {
+                return entryStrategy;
+            }
+            return Optional.absent();
+        }
+
+    }
+
     public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
 
         private final Optional<ModificationApplyOperation> entryStrategy;
@@ -698,4 +736,12 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper
 
     }
 
+    public static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
+        Set<DataSchemaNode> realChildSchemas = new HashSet<>();
+        for(DataSchemaNode augChild : schema.getChildNodes()) {
+            realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
+        }
+        return new AugmentationSchemaProxy(schema, realChildSchemas);
+    }
+
 }
index 27d320f03e656587bfabfc4b6ad95d369e55cd99..ef485bbadfcb853a2726c1af776d3429d9228ac6 100644 (file)
       <artifactId>netconf-client</artifactId>
       <version>${netconf.version}</version>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-config-dispatcher</artifactId>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>sal-common-util</artifactId>
index ddaf6ea6c378ae7728a00cff8297c82650b3a8d9..6e924221cf36387ea146d597922a90c545f3aa3a 100644 (file)
@@ -9,7 +9,8 @@ package org.opendaylight.controller.config.yang.md.sal.connector.netconf;
 
 import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
 import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
-import io.netty.channel.EventLoopGroup;
+
+import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.GlobalEventExecutor;
 
 import java.io.File;
@@ -20,10 +21,12 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher;
-import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
 import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
+import org.opendaylight.controller.sal.connect.netconf.NetconfDeviceListener;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.TimedReconnectStrategy;
 import org.opendaylight.yangtools.yang.model.util.repo.AbstractCachingSchemaSourceProvider;
@@ -69,6 +72,18 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         checkNotNull(getBetweenAttemptsTimeoutMillis(), betweenAttemptsTimeoutMillisJmxAttribute);
         checkCondition(getBetweenAttemptsTimeoutMillis() > 0, "must be > 0", betweenAttemptsTimeoutMillisJmxAttribute);
 
+        // FIXME BUG-944 remove backwards compatibility
+        if(getClientDispatcher() == null) {
+            checkCondition(getBossThreadGroup() != null, "Client dispatcher was not set, thread groups have to be set instead", bossThreadGroupJmxAttribute);
+            checkCondition(getWorkerThreadGroup() != null, "Client dispatcher was not set, thread groups have to be set instead", workerThreadGroupJmxAttribute);
+        }
+
+        // Check username + password in case of ssh
+        if(getTcpOnly() == false) {
+            checkNotNull(getUsername(), usernameJmxAttribute);
+            checkNotNull(getPassword(), passwordJmxAttribute);
+        }
+
     }
 
     @Override
@@ -76,42 +91,13 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
 
         getDomRegistryDependency();
         NetconfDevice device = new NetconfDevice(getIdentifier().getInstanceName());
-        String addressValue = getAddress();
-
-        Long connectionAttempts;
-        if (getMaxConnectionAttempts() != null && getMaxConnectionAttempts() > 0) {
-            connectionAttempts = getMaxConnectionAttempts();
-        } else {
-            logger.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
-            connectionAttempts = null;
-        }
-        long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
-        /*
-         * Uncomment after Switch to IP Address
-        if(getAddress().getIpv4Address() != null) {
-            addressValue = getAddress().getIpv4Address().getValue();
-        } else {
-            addressValue = getAddress().getIpv6Address().getValue();
-        }
-         */
-        double sleepFactor = 1.0;
-        int minSleep = 1000;
-        Long maxSleep = null;
-        Long deadline = null;
-        ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(),
-                minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
-
-        device.setReconnectStrategy(strategy);
-
-        InetAddress addr = InetAddresses.forString(addressValue);
-        InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue());
 
+        device.setClientConfig(getClientConfig(device));
 
         device.setProcessingExecutor(getGlobalProcessingExecutor());
 
-        device.setSocketAddress(socketAddress);
         device.setEventExecutor(getEventExecutorDependency());
-        device.setDispatcher(createDispatcher(clientConnectionTimeoutMillis));
+        device.setDispatcher(getClientDispatcher() == null ? createDispatcher() : getClientDispatcherDependency());
         device.setSchemaSourceProvider(getGlobalNetconfSchemaProvider(bundleContext));
 
         getDomRegistryDependency().registerProvider(device, bundleContext);
@@ -120,12 +106,7 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
     }
 
     private ExecutorService getGlobalProcessingExecutor() {
-        if(GLOBAL_PROCESSING_EXECUTOR == null) {
-
-            GLOBAL_PROCESSING_EXECUTOR = Executors.newCachedThreadPool();
-
-        }
-        return GLOBAL_PROCESSING_EXECUTOR;
+        return GLOBAL_PROCESSING_EXECUTOR == null ? Executors.newCachedThreadPool() : GLOBAL_PROCESSING_EXECUTOR;
     }
 
     private synchronized AbstractCachingSchemaSourceProvider<String, InputStream> getGlobalNetconfSchemaProvider(BundleContext bundleContext) {
@@ -139,18 +120,64 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         return GLOBAL_NETCONF_SOURCE_PROVIDER;
     }
 
-    private NetconfClientDispatcher createDispatcher(long clientConnectionTimeoutMillis) {
-        EventLoopGroup bossGroup = getBossThreadGroupDependency();
-        EventLoopGroup workerGroup = getWorkerThreadGroupDependency();
-        if(getTcpOnly()) {
-            return new NetconfClientDispatcher( bossGroup, workerGroup, clientConnectionTimeoutMillis);
-        } else {
-            AuthenticationHandler authHandler = new LoginPassword(getUsername(),getPassword());
-            return new NetconfSshClientDispatcher(authHandler , bossGroup, workerGroup, clientConnectionTimeoutMillis);
-        }
+    // FIXME BUG-944 remove backwards compatibility
+    /**
+     * @deprecated Use getClientDispatcherDependency method instead to retrieve injected dispatcher.
+     * This one creates new instance of NetconfClientDispatcher and will be removed in near future.
+     */
+    @Deprecated
+    private NetconfClientDispatcher createDispatcher() {
+        return new NetconfClientDispatcherImpl(getBossThreadGroupDependency(), getWorkerThreadGroupDependency(), new HashedWheelTimer());
     }
 
     public void setBundleContext(BundleContext bundleContext) {
         this.bundleContext = bundleContext;
     }
+
+    public NetconfClientConfiguration getClientConfig(final NetconfDevice device) {
+        InetSocketAddress socketAddress = getSocketAddress();
+        ReconnectStrategy strategy = getReconnectStrategy();
+        long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
+
+        return NetconfClientConfigurationBuilder.create()
+        .withAddress(socketAddress)
+        .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
+        .withReconnectStrategy(strategy)
+        .withSessionListener(new NetconfDeviceListener(device))
+        .withAuthHandler(new LoginPassword(getUsername(),getPassword()))
+        .withProtocol(getTcpOnly() ?
+                NetconfClientConfiguration.NetconfClientProtocol.TCP :
+                NetconfClientConfiguration.NetconfClientProtocol.SSH)
+        .build();
+    }
+
+    private ReconnectStrategy getReconnectStrategy() {
+        Long connectionAttempts;
+        if (getMaxConnectionAttempts() != null && getMaxConnectionAttempts() > 0) {
+            connectionAttempts = getMaxConnectionAttempts();
+        } else {
+            logger.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
+            connectionAttempts = null;
+        }
+        double sleepFactor = 1.0;
+        int minSleep = 1000;
+        Long maxSleep = null;
+        Long deadline = null;
+
+        return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(),
+                minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
+    }
+
+    private InetSocketAddress getSocketAddress() {
+        /*
+         * Uncomment after Switch to IP Address
+        if(getAddress().getIpv4Address() != null) {
+            addressValue = getAddress().getIpv4Address().getValue();
+        } else {
+            addressValue = getAddress().getIpv6Address().getValue();
+        }
+         */
+        InetAddress inetAddress = InetAddresses.forString(getAddress());
+        return new InetSocketAddress(inetAddress, getPort().intValue());
+    }
 }
index aa5c6f40a9a4f827c88aa97d9a72551d6e8fd94f..1209e88f5241a56b19b0140f3beb60be4120c8bd 100644 (file)
@@ -21,6 +21,7 @@ import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.toF
 import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.toRpcMessage;
 import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.wrap;
 
+import com.google.common.base.Preconditions;
 import java.io.InputStream;
 import java.net.InetSocketAddress;
 import java.net.URI;
@@ -38,6 +39,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
 import org.opendaylight.controller.sal.core.api.Provider;
@@ -121,6 +123,7 @@ public class NetconfDevice implements Provider, //
 
     private boolean rollbackSupported;
 
+    private NetconfClientConfiguration clientConfig;
 
     public NetconfDevice(String name) {
         this.name = name;
@@ -134,11 +137,12 @@ public class NetconfDevice implements Provider, //
         checkState(schemaSourceProvider != null, "Schema Source Provider must be set.");
         checkState(eventExecutor != null, "Event executor must be set.");
 
-        listener = new NetconfDeviceListener(this);
+        Preconditions.checkArgument(clientConfig.getSessionListener() instanceof NetconfDeviceListener);
+        listener = (NetconfDeviceListener) clientConfig.getSessionListener();
 
         logger.info("Starting NETCONF Client {} for address {}", name, socketAddress);
 
-        dispatcher.createClient(socketAddress, listener, reconnectStrategy);
+        dispatcher.createClient(clientConfig);
     }
 
     Optional<SchemaContext> getSchemaContext() {
@@ -222,7 +226,7 @@ public class NetconfDevice implements Provider, //
 
         logger.debug("Client capabilities {}", capabilities);
         for (QName capability : capabilities) {
-            it.addLeaf(NETCONF_INVENTORY_INITIAL_CAPABILITY, capability);
+            it.addLeaf(NETCONF_INVENTORY_INITIAL_CAPABILITY, capability.toString());
         }
 
         logger.debug("Update device state transaction " + transaction.getIdentifier()
@@ -464,6 +468,11 @@ public class NetconfDevice implements Provider, //
     public void setDispatcher(final NetconfClientDispatcher dispatcher) {
         this.dispatcher = dispatcher;
     }
+
+    public void setClientConfig(final NetconfClientConfiguration clientConfig) {
+        this.clientConfig = clientConfig;
+    }
+
 }
 
 class NetconfDeviceSchemaContextProvider {
index 1dfc3b44d3191bf00427d9e5908ff0f68f7517e0..68667f0143489cf4f8f633b641224e68d5ca73e8 100644 (file)
@@ -41,8 +41,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
-class NetconfDeviceListener implements NetconfClientSessionListener {
-
+public class NetconfDeviceListener implements NetconfClientSessionListener {
     private static final class Request {
         final UncancellableFuture<RpcResult<CompositeNode>> future;
         final NetconfMessage request;
index f0b711d368595dede27c14030b4d0d4ef64112a6..55e17c56b38e5d47b656ad37f7e5c9e5f11e78db 100644 (file)
@@ -135,7 +135,7 @@ public class NetconfMapping {
             SchemaContext schemaContext = ctx.get();
             Set<NotificationDefinition> notifications = schemaContext.getNotifications();
             Document document = message.getDocument();
-            return XmlDocumentUtils.notificationToDomNodes(document, Optional.fromNullable(notifications));
+            return XmlDocumentUtils.notificationToDomNodes(document, Optional.fromNullable(notifications), ctx.get());
         }
         return null;
     }
@@ -192,7 +192,7 @@ public class NetconfMapping {
                 rawRpc = it.toInstance();
                 // sys(xmlData)
             } else {
-                rawRpc = (CompositeNode) toCompositeNode(message.getDocument());
+                rawRpc = (CompositeNode) toCompositeNode(message, context);
             }
         else {
             rawRpc = (CompositeNode) toCompositeNode(message.getDocument());
index abd935dd63e177ddfe23b1de713891351080c3ab..31c6bd0138b41b4fc06f102dc8736f35cce0681a 100644 (file)
@@ -59,7 +59,7 @@ class NetconfRemoteSchemaSourceProvider implements SchemaSourceProvider<String>
                     return Optional.of(schemaBody);
                 }
             }
-            logger.warn("YANG shcema was not successfully retrieved.");
+            logger.warn("YANG shcema was not successfully retrieved. Errors: {}", schemaReply.getErrors());
         } catch (InterruptedException | ExecutionException e) {
             logger.warn("YANG shcema was not successfully retrieved.", e);
         }
index f0fa452dc5c989138481a50ac89b120f02edb03c..d4dad11ec3b4f70e67ede2e1ddc4f690d59e9b52 100644 (file)
@@ -7,10 +7,11 @@ module odl-sal-netconf-connector-cfg {
        import threadpool {prefix th;}
        import netty {prefix netty;}
        import opendaylight-md-sal-dom {prefix dom;}
+    import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; }
 
     description
         "Service definition for Binding Aware MD-SAL.";
+
     revision "2013-10-28" {
         description
             "Initial revision";
@@ -26,7 +27,7 @@ module odl-sal-netconf-connector-cfg {
         leaf address {
             type string;
         }
-    
+
         leaf port {
             type uint32;
         }
@@ -36,7 +37,7 @@ module odl-sal-netconf-connector-cfg {
     augment "/config:modules/config:module/config:configuration" {
         case sal-netconf-connector {
             when "/config:modules/config:module/config:type = 'sal-netconf-connector'";
-            
+
             leaf address {
                 type string;
             }
@@ -44,7 +45,7 @@ module odl-sal-netconf-connector-cfg {
             leaf port {
                 type uint32;
             }
-            
+
             leaf tcp-only {
                 type boolean;
             }
@@ -52,10 +53,11 @@ module odl-sal-netconf-connector-cfg {
             leaf username {
                 type string;
             }
-            
+
             leaf password {
                 type string;
             }
+
             container dom-registry {
                 uses config:service-ref {
                     refine type {
@@ -65,17 +67,25 @@ module odl-sal-netconf-connector-cfg {
                 }
             }
 
+            // FIXME BUG-944 remove backwards compatibility
+            // Deprecated, replaced by client dispatcher.
+            // This dependency will be removed in near future and all configurations of netconf-connector need to be changed to use dispatcher dependency.
             container boss-thread-group {
                 uses config:service-ref {
                     refine type {
+                        mandatory false;
                         config:required-identity netty:netty-threadgroup;
                     }
                 }
             }
 
+            // FIXME BUG-944 remove backwards compatibility
+            // Deprecated, replaced by client dispatcher.
+            // This dependency will be removed in near future and all configurations of netconf-connector need to be changed to use dispatcher dependency.
             container worker-thread-group {
                 uses config:service-ref {
                     refine type {
+                        mandatory false;
                         config:required-identity netty:netty-threadgroup;
                     }
                 }
@@ -89,6 +99,16 @@ module odl-sal-netconf-connector-cfg {
                 }
             }
 
+            // Replaces thread group dependencies
+            container client-dispatcher {
+                uses config:service-ref {
+                    refine type {
+                        mandatory false;
+                        config:required-identity cfg-net:netconf-client-dispatcher;
+                    }
+                }
+            }
+
             leaf connection-timeout-millis {
                 description "Specifies timeout in milliseconds after which connection must be established.";
                 type uint32;
@@ -101,7 +121,6 @@ module odl-sal-netconf-connector-cfg {
                 default 0; // retry forever
             }
 
-
             leaf between-attempts-timeout-millis {
                 description "Timeout in milliseconds to wait between connection attempts.";
                 type uint16;
index a0bd99c5d2cc3dfc4b822125f43bdf104c8663ba..f1901d711259f1907aeb9f94817ffbf84694fffd 100644 (file)
@@ -588,7 +588,11 @@ class RestconfImpl implements RestconfService {
         }
         if (node instanceof CompositeNodeWrapper) {
             if ((node  as CompositeNodeWrapper).changeAllowed) {
-                normalizeNode(node as CompositeNodeWrapper, schema, null, mountPoint)
+                try {
+                    normalizeNode(node as CompositeNodeWrapper, schema, null, mountPoint)
+                } catch (NumberFormatException e) {
+                    throw new ResponseException(BAD_REQUEST,e.message)
+                }
             }
             return (node as CompositeNodeWrapper).unwrap()
         }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java
new file mode 100644 (file)
index 0000000..767aaf3
--- /dev/null
@@ -0,0 +1,59 @@
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class CodecsExceptionsCatchingTest extends JerseyTest {
+
+    private static RestconfImpl restConf;
+    private static ControllerContext controllerContext = ControllerContext.getInstance();
+
+    @BeforeClass
+    public static void init() throws FileNotFoundException {
+        restConf = RestconfImpl.getInstance();
+        controllerContext = ControllerContext.getInstance();
+        SchemaContext schemaContext = TestUtils.loadSchemaContext("/decoding-exception/yang");
+        controllerContext.setGlobalSchema(schemaContext);
+        restConf.setControllerContext(controllerContext);
+    }
+
+    @Override
+    protected Application configure() {
+        /* enable/disable Jersey logs to console */
+        // enable(TestProperties.LOG_TRAFFIC);
+        // enable(TestProperties.DUMP_ENTITY);
+        // enable(TestProperties.RECORD_LOG_LEVEL);
+        // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+        ResourceConfig resourceConfig = new ResourceConfig();
+        resourceConfig = resourceConfig.registerInstances(restConf, StructuredDataToXmlProvider.INSTANCE,
+                StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
+                JsonToCompositeNodeProvider.INSTANCE);
+        return resourceConfig;
+    }
+
+    @Test
+    public void StringToNumberConversionError() {
+        Response response = target("/config/number:cont").request(MediaType.APPLICATION_XML).put(
+                Entity.entity("<cont xmlns=\"number\"><lf>3f</lf></cont>", MediaType.APPLICATION_XML));
+        String exceptionMessage = response.readEntity(String.class);
+        assertTrue(exceptionMessage.contains("Incorrect lexical representation of Integer value: 3f"));
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/decoding-exception/yang/number.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/decoding-exception/yang/number.yang
new file mode 100644 (file)
index 0000000..c463882
--- /dev/null
@@ -0,0 +1,17 @@
+ module number {
+
+   namespace "number";
+   prefix "number";
+
+   revision 2014-04-24 {
+   }
+
+    
+
+    container cont {
+        leaf lf {
+            type uint8;
+        }
+        
+    }    
+ }
index 4222daae13324826e3bee2acd15edb408fab04aa..5c8b20a4e36bacdad1c0a5a041d94ee67e87f406 100644 (file)
   </dependencies>
 
   <build>
-    <pluginManagement>
-      <plugins>
-        <!--This plugin's configuration is used to store Eclipse 
-                    m2e settings only. It has no influence on the Maven build itself. -->
-        <plugin>
-          <groupId>org.eclipse.m2e</groupId>
-          <artifactId>lifecycle-mapping</artifactId>
-          <version>1.0.0</version>
-          <configuration>
-            <lifecycleMappingMetadata>
-              <pluginExecutions>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.opendaylight.yangtools</groupId>
-                    <artifactId>yang-maven-plugin</artifactId>
-                    <versionRange>[0.5,)</versionRange>
-                    <goals>
-                      <goal>generate-sources</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
-              </pluginExecutions>
-            </lifecycleMappingMetadata>
-          </configuration>
-        </plugin>
-      </plugins>
-    </pluginManagement>
     <plugins>
       <plugin>
         <groupId>org.opendaylight.yangtools</groupId>
index 4a58579b13fd542936f876ddad48c7ebaabcb8a5..167fb21ffdc763f6cda840fc42b6b1e6aed03c7f 100644 (file)
@@ -20,8 +20,8 @@ abstract class AbstractListeningStatsTracker<I, K> extends AbstractStatsTracker<
     private static final Logger logger = LoggerFactory.getLogger(AbstractListeningStatsTracker.class);
     private ListenerRegistration<?> reg;
 
-    protected AbstractListeningStatsTracker(FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    protected AbstractListeningStatsTracker(FlowCapableContext context) {
+        super(context);
     }
 
     protected abstract InstanceIdentifier<?> listenPath();
index c29b6a7730ced4f24374d2e4e67a650f3ed69293..e922656d919f5726de7fe19d743458a26f08a531 100644 (file)
@@ -32,6 +32,9 @@ import com.google.common.util.concurrent.JdkFutureAdapters;
 
 abstract class AbstractStatsTracker<I, K> {
     private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class);
+    
+    private static final int WAIT_FOR_REQUEST_CYCLE = 2;
+    
     private final FutureCallback<RpcResult<? extends TransactionAware>> callback =
             new FutureCallback<RpcResult<? extends TransactionAware>>() {
         @Override
@@ -62,11 +65,11 @@ abstract class AbstractStatsTracker<I, K> {
 
     private final Map<K, Long> trackedItems = new HashMap<>();
     private final FlowCapableContext context;
-    private final long lifetimeNanos;
+    private long requestCounter;
 
-    protected AbstractStatsTracker(final FlowCapableContext context, final long lifetimeNanos) {
+    protected AbstractStatsTracker(final FlowCapableContext context) {
         this.context = Preconditions.checkNotNull(context);
-        this.lifetimeNanos = lifetimeNanos;
+        this.requestCounter = 0;
     }
 
     protected final InstanceIdentifierBuilder<Node> getNodeIdentifierBuilder() {
@@ -89,24 +92,32 @@ abstract class AbstractStatsTracker<I, K> {
         return context.startDataModification();
     }
 
+    public final synchronized void increaseRequestCounter(){
+        this.requestCounter++;
+    }
     protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item);
     protected abstract K updateSingleStat(DataModificationTransaction trans, I item);
+    public abstract void request();
 
     public final synchronized void updateStats(List<I> list) {
-        final Long expiryTime = System.nanoTime() + lifetimeNanos;
+
         final DataModificationTransaction trans = startTransaction();
 
         for (final I item : list) {
-            trackedItems.put(updateSingleStat(trans, item), expiryTime);
+            trackedItems.put(updateSingleStat(trans, item), requestCounter);
         }
 
         trans.commit();
     }
 
-    public final synchronized void cleanup(final DataModificationTransaction trans, long now) {
+    /**
+     * Statistics will be cleaned up if not update in last two request cycles.
+     * @param trans
+     */
+    public final synchronized void cleanup(final DataModificationTransaction trans) {
         for (Iterator<Entry<K, Long>> it = trackedItems.entrySet().iterator();it.hasNext();){
             Entry<K, Long> e = it.next();
-            if (now > e.getValue()) {
+            if (requestCounter >= e.getValue()+WAIT_FOR_REQUEST_CYCLE) {
                 cleanupSingleStat(trans, e.getKey());
                 it.remove();
             }
index 90ddc28acd0066e72e8e134a49c0a786b6f49b4b..06d6e821122617aa1642e3cfd6a5d46808f8518a 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
+import java.util.Collection;
 import java.util.Map.Entry;
 
 import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
@@ -37,12 +38,17 @@ import org.slf4j.LoggerFactory;
 final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
     private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class);
     private final OpendaylightFlowStatisticsService flowStatsService;
+    private FlowTableStatsTracker flowTableStats;
     private int unaccountedFlowsCounter = 1;
 
-    FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) {
+        super(context);
         this.flowStatsService = flowStatsService;
     }
+    FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, FlowTableStatsTracker flowTableStats) {
+        this(flowStatsService, context);
+        this.flowTableStats = flowTableStats;
+    }
 
     @Override
     protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) {
@@ -203,6 +209,20 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
         return "Flow";
     }
 
+    @Override
+    public void request() {
+        // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
+        //        comes back -- we do not have any tables anyway.
+        final Collection<TableKey> tables = flowTableStats.getTables();
+        logger.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size());
+        for (final TableKey key : tables) {
+            logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef());
+            this.requestAggregateFlows(key);
+        }
+
+        this.requestAllFlowsAllTables();
+        
+    }
     public void requestAllFlowsAllTables() {
         if (flowStatsService != null) {
             final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
index 3fe68c111a1549bc6c9df7b9b19803590ffad94b..a160f6d467ca6731a8c4d485250d6697cec8b97e 100644 (file)
@@ -30,8 +30,8 @@ final class FlowTableStatsTracker extends AbstractStatsTracker<FlowTableAndStati
     private final Set<TableKey> tables = Collections.unmodifiableSet(privateTables);
     private final OpendaylightFlowTableStatisticsService flowTableStatsService;
 
-    FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context) {
+        super(context);
         this.flowTableStatsService = flowTableStatsService;
     }
 
@@ -61,6 +61,7 @@ final class FlowTableStatsTracker extends AbstractStatsTracker<FlowTableAndStati
         return item;
     }
 
+    @Override
     public void request() {
         if (flowTableStatsService != null) {
             final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder();
index 8aebd6b2491a00ce27bfb8e1093517029ea87cf3..e180aaf5fc94de8b609bcab6803843c36da2fac5 100644 (file)
@@ -29,8 +29,8 @@ final class GroupDescStatsTracker extends AbstractListeningStatsTracker<GroupDes
     private static final Logger logger = LoggerFactory.getLogger(GroupDescStatsTracker.class);
     private final OpendaylightGroupStatisticsService groupStatsService;
 
-    public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context, final long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context) {
+        super(context);
         this.groupStatsService = groupStatsService;
     }
 
@@ -70,6 +70,7 @@ final class GroupDescStatsTracker extends AbstractListeningStatsTracker<GroupDes
         return "Group Descriptor";
     }
 
+    @Override
     public void request() {
         if (groupStatsService != null) {
             final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
index 1af8e4e9f1a2cf891795d06f967ca0b12307c730..9735fea069325d7f12a87e02563a9afb24205ccf 100644 (file)
@@ -31,8 +31,8 @@ final class GroupStatsTracker extends AbstractListeningStatsTracker<GroupStats,
     private static final Logger logger = LoggerFactory.getLogger(GroupStatsTracker.class);
     private final OpendaylightGroupStatisticsService groupStatsService;
 
-    GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context) {
+        super(context);
         this.groupStatsService = Preconditions.checkNotNull(groupStatsService);
     }
 
@@ -72,6 +72,7 @@ final class GroupStatsTracker extends AbstractListeningStatsTracker<GroupStats,
         return "Group";
     }
 
+    @Override
     public void request() {
         final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
         input.setNode(getNodeRef());
index 4b9592570565fc94d423702a7cff9923d110895f..e8b7fb7164d6d749a4b2427bc9ce591f4f0a5b54 100644 (file)
@@ -29,8 +29,8 @@ final class MeterConfigStatsTracker extends AbstractListeningStatsTracker<MeterC
     private static final Logger logger = LoggerFactory.getLogger(MeterConfigStatsTracker.class);
     private final OpendaylightMeterStatisticsService meterStatsService;
 
-    protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context) {
+        super(context);
         this.meterStatsService = meterStatsService;
     }
 
@@ -62,6 +62,7 @@ final class MeterConfigStatsTracker extends AbstractListeningStatsTracker<MeterC
         return item;
     }
 
+    @Override
     public void request() {
         if (meterStatsService != null) {
             GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
index 091cbcc1a078f88d54cde3eaa9300da97aaed8c2..b373020f1ca26cbd2e08faa7b033c65731344764 100644 (file)
@@ -29,8 +29,8 @@ final class MeterStatsTracker extends AbstractListeningStatsTracker<MeterStats,
     private static final Logger logger = LoggerFactory.getLogger(MeterStatsTracker.class);
     private final OpendaylightMeterStatisticsService meterStatsService;
 
-    MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context) {
+        super(context);
         this.meterStatsService = meterStatsService;
     }
 
@@ -61,6 +61,7 @@ final class MeterStatsTracker extends AbstractListeningStatsTracker<MeterStats,
         return item;
     }
 
+    @Override
     public void request() {
         if (meterStatsService != null) {
             GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
index 00bd27402fc3c45c82f0f9d06c8a5a562ea76a97..701911d9a2c307c03ecd48c75bfcd4099ba2490f 100644 (file)
@@ -25,8 +25,8 @@ final class NodeConnectorStatsTracker extends AbstractStatsTracker<NodeConnector
     private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsTracker.class);
     private final OpendaylightPortStatisticsService portStatsService;
 
-    NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context) {
+        super(context);
         this.portStatsService = portStatsService;
     }
 
@@ -73,6 +73,7 @@ final class NodeConnectorStatsTracker extends AbstractStatsTracker<NodeConnector
         return item;
     }
 
+    @Override
     public void request() {
         if (portStatsService != null) {
             final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder();
index 5ace260251673bb9fa42b9da14a95a5ece724b4c..dbcbab982a9aec997e37a2fb09e763bb3f3c5f96 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -73,6 +72,7 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
     private static final int NUMBER_OF_WAIT_CYCLES = 2;
 
     private final MultipartMessageManager msgManager;
+    private final StatisticsRequestScheduler srScheduler;
     private final InstanceIdentifier<Node> targetNodeIdentifier;
     private final FlowStatsTracker flowStats;
     private final FlowTableStatsTracker flowTableStats;
@@ -103,23 +103,25 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
             final OpendaylightGroupStatisticsService groupStatsService,
             final OpendaylightMeterStatisticsService meterStatsService,
             final OpendaylightPortStatisticsService portStatsService,
-            final OpendaylightQueueStatisticsService queueStatsService) {
+            final OpendaylightQueueStatisticsService queueStatsService, 
+            final StatisticsRequestScheduler srScheduler) {
         this.dps = Preconditions.checkNotNull(dps);
         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
+        this.srScheduler = Preconditions.checkNotNull(srScheduler);
         this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
         this.targetNodeRef = new NodeRef(targetNodeIdentifier);
 
         final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
 
         msgManager = new MultipartMessageManager(lifetimeNanos);
-        flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
-        flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
-        groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
-        groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
-        meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
-        meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
-        nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
-        queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
+        flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this);
+        flowStats = new FlowStatsTracker(flowStatsService, this, flowTableStats);
+        groupDescStats = new GroupDescStatsTracker(groupStatsService, this);
+        groupStats = new GroupStatsTracker(groupStatsService, this);
+        meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this);
+        meterStats = new MeterStatsTracker(meterStatsService, this);
+        nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this);
+        queueStats = new QueueStatsTracker(queueStatsService, this);
     }
 
     public NodeKey getTargetNodeKey() {
@@ -138,7 +140,9 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
 
     @Override
     public DataModificationTransaction startDataModification() {
-        return dps.beginTransaction();
+        DataModificationTransaction dmt = dps.beginTransaction();
+        dmt.registerListener(this.srScheduler);
+        return dmt;
     }
 
     public synchronized void updateGroupDescStats(TransactionAware transaction, List<GroupDescStats> list) {
@@ -186,7 +190,7 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
     public synchronized void updateAggregateFlowStats(TransactionAware transaction, AggregateFlowStatistics flowStats) {
         final Short tableId = msgManager.isExpectedTableTransaction(transaction);
         if (tableId != null) {
-            final DataModificationTransaction trans = dps.beginTransaction();
+            final DataModificationTransaction trans = this.startDataModification();
             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
 
@@ -214,7 +218,7 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
     }
 
     public synchronized void updateGroupFeatures(GroupFeatures notification) {
-        final DataModificationTransaction trans = dps.beginTransaction();
+        final DataModificationTransaction trans = this.startDataModification();
 
         final NodeBuilder nodeData = new NodeBuilder();
         nodeData.setKey(targetNodeKey);
@@ -232,7 +236,7 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
     }
 
     public synchronized void updateMeterFeatures(MeterFeatures features) {
-        final DataModificationTransaction trans = dps.beginTransaction();
+        final DataModificationTransaction trans = this.startDataModification();
 
         final NodeBuilder nodeData = new NodeBuilder();
         nodeData.setKey(targetNodeKey);
@@ -250,16 +254,15 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
     }
 
     public synchronized void cleanStaleStatistics() {
-        final DataModificationTransaction trans = dps.beginTransaction();
-        final long now = System.nanoTime();
-
-        flowStats.cleanup(trans, now);
-        groupDescStats.cleanup(trans, now);
-        groupStats.cleanup(trans, now);
-        meterConfigStats.cleanup(trans, now);
-        meterStats.cleanup(trans, now);
-        nodeConnectorStats.cleanup(trans, now);
-        queueStats.cleanup(trans, now);
+        final DataModificationTransaction trans = this.startDataModification();
+
+        flowStats.cleanup(trans);
+        groupDescStats.cleanup(trans);
+        groupStats.cleanup(trans);
+        meterConfigStats.cleanup(trans);
+        meterStats.cleanup(trans);
+        nodeConnectorStats.cleanup(trans);
+        queueStats.cleanup(trans);
         msgManager.cleanStaleTransactionIds();
 
         trans.commit();
@@ -268,26 +271,23 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo
     public synchronized void requestPeriodicStatistics() {
         logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
 
-        flowTableStats.request();
-
-        // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
-        //        comes back -- we do not have any tables anyway.
-        final Collection<TableKey> tables = flowTableStats.getTables();
-        logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
-        for (final TableKey key : tables) {
-            logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
-            flowStats.requestAggregateFlows(key);
-        }
-
-        flowStats.requestAllFlowsAllTables();
-        nodeConnectorStats.request();
-        groupStats.request();
-        groupDescStats.request();
-        meterStats.request();
-        meterConfigStats.request();
-        queueStats.request();
+        this.srScheduler.addRequestToSchedulerQueue(flowTableStats);
+
+        this.srScheduler.addRequestToSchedulerQueue(flowStats);
+        
+        this.srScheduler.addRequestToSchedulerQueue(nodeConnectorStats);
+        
+        this.srScheduler.addRequestToSchedulerQueue(groupStats);
+        
+        this.srScheduler.addRequestToSchedulerQueue(groupDescStats);
+        
+        this.srScheduler.addRequestToSchedulerQueue(meterStats);
+        
+        this.srScheduler.addRequestToSchedulerQueue(meterConfigStats);
+        
+        this.srScheduler.addRequestToSchedulerQueue(queueStats);
     }
-
+    
     public synchronized void start(final Timer timer) {
         flowStats.start(dps);
         groupDescStats.start(dps);
index f187c7082e6e3b2093e2e0b0654a406dd9315950..6f93eeb6172dcdaf24db8301214abe12d92857e0 100644 (file)
@@ -36,8 +36,8 @@ final class QueueStatsTracker extends AbstractListeningStatsTracker<QueueIdAndSt
     private static final Logger logger = LoggerFactory.getLogger(QueueStatsTracker.class);
     private final OpendaylightQueueStatisticsService queueStatsService;
 
-    QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context, long lifetimeNanos) {
-        super(context, lifetimeNanos);
+    QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context) {
+        super(context);
         this.queueStatsService = queueStatsService;
     }
 
@@ -82,6 +82,7 @@ final class QueueStatsTracker extends AbstractListeningStatsTracker<QueueIdAndSt
         return queueEntry;
     }
 
+    @Override
     public void request() {
         if (queueStatsService != null) {
             GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
index 892d304daa8d6cd20c7010082f2698cb8de90266..d8bea7c63a4606fffaed51a9dce5fe889dca2d36 100644 (file)
@@ -66,9 +66,12 @@ public class StatisticsProvider implements AutoCloseable {
     private OpendaylightFlowTableStatisticsService flowTableStatsService;
 
     private OpendaylightQueueStatisticsService queueStatsService;
+    
+    private final StatisticsRequestScheduler srScheduler;
 
     public StatisticsProvider(final DataProviderService dataService) {
         this.dps = Preconditions.checkNotNull(dataService);
+        this.srScheduler = new StatisticsRequestScheduler();
     }
 
     private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this);
@@ -86,7 +89,8 @@ public class StatisticsProvider implements AutoCloseable {
         portStatsService = rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class);
         flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class);
         queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class);
-
+        this.srScheduler.start();
+        
         // Start receiving notifications
         this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
 
@@ -144,7 +148,7 @@ public class StatisticsProvider implements AutoCloseable {
 
             final NodeStatisticsHandler h = new NodeStatisticsHandler(dps, key,
                     flowStatsService, flowTableStatsService, groupStatsService,
-                    meterStatsService, portStatsService, queueStatsService);
+                    meterStatsService, portStatsService, queueStatsService,srScheduler);
             final NodeStatisticsHandler old = handlers.putIfAbsent(key.getId(), h);
             if (old == null) {
                 spLogger.debug("Started node handler for {}", key.getId());
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java
new file mode 100644 (file)
index 0000000..9ebfd6f
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Main responsibility of the class is to check the MD-SAL data store read/write
+ * transaction accumulation level and send statistics request if number of pending 
+ * read/write transactions are zero.
+ * @author avishnoi@in.ibm.com
+ *
+ */
+@SuppressWarnings("rawtypes")
+public class StatisticsRequestScheduler implements DataTransactionListener {
+
+    private static final Logger srsLogger = LoggerFactory.getLogger(StatisticsRequestScheduler.class);
+    private final Timer timer = new Timer("request-monitor", true);
+
+    // We need ordered retrieval, and O(1) contains operation
+    private final Map<AbstractStatsTracker,Integer> requestQueue = 
+            Collections.synchronizedMap(new LinkedHashMap<AbstractStatsTracker,Integer>());
+    
+    private Long PendingTransactions;
+    
+    private long lastRequestTime = System.nanoTime();
+    
+    private static final long REQUEST_MONITOR_INTERVAL = 1000;
+    
+    private final TimerTask task = new TimerTask() {
+        @Override
+        public void run() {
+            long now = System.nanoTime();
+            if(now > lastRequestTime+TimeUnit.MILLISECONDS.toNanos(REQUEST_MONITOR_INTERVAL)){
+                requestStatistics();
+            }
+        }
+    };
+
+    public StatisticsRequestScheduler(){
+        PendingTransactions = (long) 0;
+    }
+    
+    public void addRequestToSchedulerQueue(AbstractStatsTracker statsRequest){
+        requestQueue.put(statsRequest, null);
+    }
+    
+    public AbstractStatsTracker getNextRequestFromSchedulerQueue(){
+        //Remove first element
+        AbstractStatsTracker stats = null;
+        synchronized(requestQueue){
+            Iterator<Map.Entry<AbstractStatsTracker, Integer>> nodesItr = requestQueue.entrySet().iterator();
+            if(nodesItr.hasNext()){
+                stats = nodesItr.next().getKey();
+                srsLogger.debug("{} chosen up for execution",stats.getNodeRef());
+                nodesItr.remove();
+                return stats;
+            }
+        }
+        return stats;
+    }
+
+    private void requestStatistics(){
+        AbstractStatsTracker stats = this.getNextRequestFromSchedulerQueue();
+        if(stats != null) {
+            stats.request();
+            stats.increaseRequestCounter();
+        }
+    }
+    @Override
+    public void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status) {
+        
+        AbstractStatsTracker stats = null;
+        synchronized(PendingTransactions){
+            switch(status){
+            case SUBMITED:
+                this.PendingTransactions++;
+                break;
+            case COMMITED:
+            case FAILED:
+                this.PendingTransactions--;
+                if(PendingTransactions == 0){
+                    lastRequestTime = System.nanoTime();
+                    stats = this.getNextRequestFromSchedulerQueue();
+                }
+                srsLogger.debug("Pending MD-SAL transactions : {} & Scheduler queue size : {}",this.PendingTransactions,this.requestQueue.size());
+                break;
+            default:
+                break;
+            }
+        }
+        if(stats != null){
+            stats.request();
+            stats.increaseRequestCounter();
+        }
+    }
+    
+    public void start(){
+        timer.schedule(task, 0, REQUEST_MONITOR_INTERVAL);
+    }
+}
index fd44315499acdcb127b519ebca77c161035958a3..ce77fdc08ed801219fb58f72b6d356c32ae77449 100644 (file)
@@ -41,7 +41,7 @@
         <artifactId>maven-bundle-plugin</artifactId>
         <configuration>
           <instructions>
-            <Export-Package>org.opendaylight.controller.netconf.client,</Export-Package>
+            <Export-Package>org.opendaylight.controller.netconf.client.*,</Export-Package>
             <Import-Package>com.google.common.base,
                             com.google.common.collect,
                             io.netty.channel,
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
deleted file mode 100644 (file)
index d98211d..0000000
+++ /dev/null
@@ -1,171 +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.client;
-
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.Set;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.TimedReconnectStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Sets;
-
-/**
- * @deprecated Use {@link NetconfClientDispatcher.createClient()} or {@link NetconfClientDispatcher.createReconnectingClient()} instead.
- */
-@Deprecated
-public class NetconfClient implements Closeable {
-
-    private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
-
-    public static final int DEFAULT_CONNECT_TIMEOUT = 5000;
-    private final NetconfClientDispatcher dispatch;
-    private final String label;
-    private final NetconfClientSession clientSession;
-    private final NetconfClientSessionListener sessionListener;
-    private final long sessionId;
-    private final InetSocketAddress address;
-
-    // TODO test reconnecting constructor
-    public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectionAttempts,
-            int attemptMsTimeout, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        this(clientLabelForLogging, address, getReconnectStrategy(connectionAttempts, attemptMsTimeout),
-                netconfClientDispatcher);
-    }
-
-    private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        this.label = clientLabelForLogging;
-        dispatch = netconfClientDispatcher;
-        sessionListener = new SimpleNetconfClientSessionListener();
-        Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
-        this.address = address;
-        clientSession = get(clientFuture);
-        this.sessionId = clientSession.getSessionId();
-    }
-
-    private NetconfClientSession get(Future<NetconfClientSession> clientFuture) throws InterruptedException {
-        try {
-            return clientFuture.get();
-        } catch (CancellationException e) {
-            throw new RuntimeException("Cancelling " + this, e);
-        } catch (ExecutionException e) {
-            throw new IllegalStateException("Unable to create " + this, e);
-        }
-    }
-
-    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher);
-    }
-
-    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address,
-            ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException {
-        return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener);
-    }
-
-    public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
-            NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        this(clientLabelForLogging, address,
-                new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), netconfClientDispatcher);
-    }
-
-    public NetconfClient(String clientLabelForLogging, InetSocketAddress address,
-            NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
-                DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
-    }
-
-    public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy,
-            NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException{
-        this.label = clientLabelForLogging;
-        dispatch = netconfClientDispatcher;
-        sessionListener = listener;
-        Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strategy);
-        this.address = address;
-        clientSession = get(clientFuture);
-        this.sessionId = clientSession.getSessionId();
-    }
-
-    public Future<NetconfMessage> sendRequest(NetconfMessage message) {
-        return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
-    }
-
-    /**
-     * @deprecated Use {@link sendRequest} instead
-     */
-    @Deprecated
-    public NetconfMessage sendMessage(NetconfMessage message) throws ExecutionException, InterruptedException, TimeoutException {
-        return sendMessage(message, 5, 1000);
-    }
-
-    /**
-     * @deprecated Use {@link sendRequest} instead
-     */
-    @Deprecated
-    public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) throws ExecutionException, InterruptedException, TimeoutException {
-        final Stopwatch stopwatch = new Stopwatch().start();
-
-        try {
-            return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS);
-        } finally {
-            stopwatch.stop();
-            logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS));
-        }
-    }
-
-    @Override
-    public void close() throws IOException {
-        clientSession.close();
-    }
-
-    public NetconfClientDispatcher getNetconfClientDispatcher() {
-        return dispatch;
-    }
-
-    private static ReconnectStrategy getReconnectStrategy(int connectionAttempts, int attemptMsTimeout) {
-        return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
-                Long.valueOf(connectionAttempts), null);
-    }
-
-    @Override
-    public String toString() {
-        final StringBuffer sb = new StringBuffer("NetconfClient{");
-        sb.append("label=").append(label);
-        sb.append(", sessionId=").append(sessionId);
-        sb.append('}');
-        return sb.toString();
-    }
-
-    public long getSessionId() {
-        return sessionId;
-    }
-
-    public Set<String> getCapabilities() {
-        Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
-        return Sets.newHashSet(clientSession.getServerCapabilities());
-    }
-
-    public NetconfClientSession getClientSession() {
-        return clientSession;
-    }
-}
index c7c723cb27b552fa51b7a7a287f66306649f35ca..37e29876f304b620e33d40490e3a9890855633c4 100644 (file)
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * 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.client;
 
-import com.google.common.base.Optional;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
-import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.protocol.framework.AbstractDispatcher;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
-import org.opendaylight.protocol.framework.SessionListenerFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.Closeable;
-import java.net.InetSocketAddress;
-
-public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
-
-    private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcher.class);
-
-    private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
-    private final HashedWheelTimer timer;
-
-    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
-            long clientConnectionTimeoutMillis) {
-        super(bossGroup, workerGroup);
-        timer = new HashedWheelTimer();
-        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
-                Optional.<NetconfHelloMessageAdditionalHeader> absent(), clientConnectionTimeoutMillis);
-    }
-
-    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
-            NetconfHelloMessageAdditionalHeader additionalHeader, long connectionTimeoutMillis) {
-        super(bossGroup, workerGroup);
-        timer = new HashedWheelTimer();
-        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader),
-                connectionTimeoutMillis);
-    }
-
-    public Future<NetconfClientSession> createClient(InetSocketAddress address,
-            final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) {
-
-        return super.createClient(address, strat, new PipelineInitializer<NetconfClientSession>() {
-
-            @Override
-            public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
-                initialize(ch, promise);
-            }
-
-            private void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
-                new ClientChannelInitializer(negotiatorFactory, sessionListener).initialize(ch, promise);
-            }
-        });
-    }
-
-    public Future<Void> createReconnectingClient(final InetSocketAddress address,
-            final NetconfClientSessionListener listener,
-            final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
-        final ClientChannelInitializer init = new ClientChannelInitializer(negotiatorFactory, listener);
-
-        return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
-                new PipelineInitializer<NetconfClientSession>() {
-            @Override
-            public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
-                init.initialize(ch, promise);
-            }
-        });
-    }
-
-    private static final class ClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
-
-        private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
-        private final NetconfClientSessionListener sessionListener;
-
-        private ClientChannelInitializer(NetconfClientSessionNegotiatorFactory negotiatorFactory,
-                NetconfClientSessionListener sessionListener) {
-            this.negotiatorFactory = negotiatorFactory;
-            this.sessionListener = sessionListener;
-        }
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
 
-        @Override
-        public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
-                super.initialize(ch,promise);
-        }
+public interface NetconfClientDispatcher {
 
-        @Override
-        protected void initializeSessionNegotiator(SocketChannel ch, Promise<NetconfClientSession> promise) {
-            ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER,  AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
-                    negotiatorFactory.getSessionNegotiator(
-                            new SessionListenerFactory<NetconfClientSessionListener>() {
-                                @Override
-                                public NetconfClientSessionListener getSessionListener() {
-                                    return sessionListener;
-                                }
-                            }, ch, promise));
-        }
-    }
+    /**
+     *
+     * Create netconf client. Network communication has to be set up based on network protocol specified in clientConfiguration
+     *
+     * @param clientConfiguration
+     * @return netconf client based on provided configuration
+     */
+    Future<NetconfClientSession> createClient(NetconfClientConfiguration clientConfiguration);
 
-    @Override
-    public void close() {
-        try {
-            timer.stop();
-        } catch (Exception e) {
-            logger.debug("Ignoring exception while closing {}", timer, e);
-        }
-    }
+    Future<Void> createReconnectingClient(NetconfReconnectingClientConfiguration clientConfiguration);
 }
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcherImpl.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcherImpl.java
new file mode 100644 (file)
index 0000000..bdebfa2
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.client;
+
+import java.io.Closeable;
+
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.protocol.framework.AbstractDispatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.Promise;
+
+public class NetconfClientDispatcherImpl extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener>
+        implements NetconfClientDispatcher, Closeable {
+
+    private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcherImpl.class);
+
+    private final Timer timer;
+
+    public NetconfClientDispatcherImpl(final EventLoopGroup bossGroup, final EventLoopGroup workerGroup, final Timer timer) {
+        super(bossGroup, workerGroup);
+        this.timer = timer;
+    }
+
+    @Override
+    public Future<NetconfClientSession> createClient(final NetconfClientConfiguration clientConfiguration) {
+        switch (clientConfiguration.getProtocol()) {
+        case TCP:
+            return createTcpClient(clientConfiguration);
+        case SSH:
+            return createSshClient(clientConfiguration);
+        }
+        throw new IllegalArgumentException("Unknown client protocol " + clientConfiguration.getProtocol());
+    }
+
+    @Override
+    public Future<Void> createReconnectingClient(final NetconfReconnectingClientConfiguration clientConfiguration) {
+        switch (clientConfiguration.getProtocol()) {
+            case TCP: return createReconnectingTcpClient(clientConfiguration);
+            case SSH: return createReconnectingSshClient(clientConfiguration);
+            default: throw new IllegalArgumentException("Unknown client protocol " + clientConfiguration.getProtocol());
+        }
+    }
+
+    private Future<NetconfClientSession> createTcpClient(final NetconfClientConfiguration currentConfiguration) {
+        logger.debug("Creating TCP client with configuration: {}", currentConfiguration);
+        return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(),
+                new PipelineInitializer<NetconfClientSession>() {
+
+                    @Override
+                    public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                        initialize(ch, promise);
+                    }
+
+                    private void initialize(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                        new TcpClientChannelInitializer(getNegotiatorFactory(currentConfiguration), currentConfiguration
+                                .getSessionListener()).initialize(ch, promise);
+                    }
+                });
+    }
+
+    private Future<Void> createReconnectingTcpClient(final NetconfReconnectingClientConfiguration currentConfiguration) {
+        logger.debug("Creating reconnecting TCP client with configuration: {}", currentConfiguration);
+        final TcpClientChannelInitializer init = new TcpClientChannelInitializer(getNegotiatorFactory(currentConfiguration),
+                currentConfiguration.getSessionListener());
+
+        return super.createReconnectingClient(currentConfiguration.getAddress(), currentConfiguration.getConnectStrategyFactory(),
+                currentConfiguration.getReconnectStrategy(), new PipelineInitializer<NetconfClientSession>() {
+                    @Override
+                    public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                        init.initialize(ch, promise);
+                    }
+                });
+    }
+
+    private Future<NetconfClientSession> createSshClient(final NetconfClientConfiguration currentConfiguration) {
+        logger.debug("Creating SSH client with configuration: {}", currentConfiguration);
+        return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(),
+                new PipelineInitializer<NetconfClientSession>() {
+
+                    @Override
+                    public void initializeChannel(final SocketChannel ch,
+                                                  final Promise<NetconfClientSession> sessionPromise) {
+                        new SshClientChannelInitializer(currentConfiguration.getAuthHandler(),
+                                getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener())
+                                .initialize(ch, sessionPromise);
+                    }
+
+                });
+    }
+
+    private Future<Void> createReconnectingSshClient(final NetconfReconnectingClientConfiguration currentConfiguration) {
+        logger.debug("Creating reconnecting SSH client with configuration: {}", currentConfiguration);
+        final SshClientChannelInitializer init = new SshClientChannelInitializer(currentConfiguration.getAuthHandler(),
+                getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener());
+
+        return super.createReconnectingClient(currentConfiguration.getAddress(), currentConfiguration.getConnectStrategyFactory(), currentConfiguration.getReconnectStrategy(),
+                new PipelineInitializer<NetconfClientSession>() {
+                    @Override
+                    public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                        init.initialize(ch, promise);
+                    }
+                });
+    }
+
+    protected NetconfClientSessionNegotiatorFactory getNegotiatorFactory(final NetconfClientConfiguration cfg) {
+        return new NetconfClientSessionNegotiatorFactory(timer, cfg.getAdditionalHeader(),
+                cfg.getConnectionTimeoutMillis());
+    }
+}
index ad50fedf6b564fbef12cfd6f8e3308b717d9515a..f4efb1fc7dc9bf56cd3176c769f72c312ee351d2 100644 (file)
@@ -8,7 +8,8 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import io.netty.channel.Channel;
+import java.util.Collection;
+
 import org.opendaylight.controller.netconf.util.AbstractNetconfSession;
 import org.opendaylight.controller.netconf.util.handler.NetconfEXICodec;
 import org.opendaylight.controller.netconf.util.handler.NetconfEXIToMessageDecoder;
@@ -18,7 +19,7 @@ import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecod
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collection;
+import io.netty.channel.Channel;
 
 public final class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
 
@@ -36,7 +37,6 @@ public final class NetconfClientSession extends AbstractNetconfSession<NetconfCl
         return capabilities;
     }
 
-
     @Override
     protected NetconfClientSession thisInstance() {
         return this;
index f8f73fc8e5296b9534e0759bc43f24bbf493521e..4e2393171afd2090a103dbdb110ed4aea71f9dca 100644 (file)
@@ -8,13 +8,14 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
+import java.util.Collection;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+
 import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
@@ -22,6 +23,7 @@ import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
+import org.opendaylight.controller.netconf.util.messages.NetconfStartExiMessage;
 import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -31,8 +33,9 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
 
 public class NetconfClientSessionNegotiator extends
         AbstractNetconfSessionNegotiator<NetconfClientSessionPreferences, NetconfClientSession, NetconfClientSessionListener>
@@ -55,19 +58,47 @@ public class NetconfClientSessionNegotiator extends
 
     @Override
     protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
-        NetconfClientSession session = super.getSessionForHelloMessage(netconfMessage);
-
-        if (shouldUseExi(netconfMessage.getDocument())){
-            logger.debug("Netconf session: {} should use exi.", session);
-            tryToStartExi(session);
+        final NetconfClientSession session = getSessionForHelloMessage(netconfMessage);
+        replaceHelloMessageInboundHandler(session);
+
+        // If exi should be used, try to initiate exi communication
+        // Call negotiationSuccessFul after exi negotiation is finished successfully or not
+        if (shouldUseExi(netconfMessage)) {
+            logger.debug("Netconf session {} should use exi.", session);
+            NetconfStartExiMessage startExiMessage = (NetconfStartExiMessage) sessionPreferences.getStartExiMessage();
+            tryToInitiateExi(session, startExiMessage);
+        // Exi is not supported, release session immediately
         } else {
-            logger.debug("Netconf session {} isn't capable using exi.", session);
+            logger.debug("Netconf session {} isn't capable of using exi.", session);
             negotiationSuccessful(session);
         }
     }
 
-    private boolean shouldUseExi(Document doc) {
-        return containsExi10Capability(doc)
+    /**
+     * Initiates exi communication by sending start-exi message and waiting for positive/negative response.
+     *
+     * @param startExiMessage
+     */
+    void tryToInitiateExi(final NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
+        channel.pipeline().addAfter(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER,
+                ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER,
+                new ExiConfirmationInboundHandler(session, startExiMessage));
+
+        session.sendMessage(startExiMessage).addListener(new ChannelFutureListener() {
+            @Override
+            public void operationComplete(final ChannelFuture f) {
+                if (!f.isSuccess()) {
+                    logger.warn("Failed to send start-exi message {} on session {}", startExiMessage, this, f.cause());
+                    channel.pipeline().remove(ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER);
+                } else {
+                    logger.trace("Start-exi message {} sent to socket on session {}", startExiMessage, this);
+                }
+            }
+        });
+    }
+
+    private boolean shouldUseExi(NetconfHelloMessage helloMsg) {
+        return containsExi10Capability(helloMsg.getDocument())
                 && containsExi10Capability(sessionPreferences.getHelloMessage().getDocument());
     }
 
@@ -81,23 +112,6 @@ public class NetconfClientSessionNegotiator extends
         return false;
     }
 
-    private void tryToStartExi(final NetconfClientSession session) {
-        final NetconfMessage startExi = sessionPreferences.getStartExiMessage();
-        session.sendMessage(startExi).addListener(new ChannelFutureListener() {
-            @Override
-            public void operationComplete(final ChannelFuture f) {
-                if (!f.isSuccess()) {
-                    logger.warn("Failed to send start-exi message {} on session {}", startExi, session, f.cause());
-                } else {
-                    logger.trace("Start-exi message {} sent to socket on session {}", startExi, session);
-                    NetconfClientSessionNegotiator.this.channel.pipeline().addAfter(
-                            AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER,
-                            new ExiConfirmationInboundHandler(session));
-                }
-            }
-        });
-    }
-
     private long extractSessionId(Document doc) {
         final Node sessionIdNode = (Node) XmlUtil.evaluateXPath(sessionIdXPath, doc, XPathConstants.NODE);
         String textContent = sessionIdNode.getTextContent();
@@ -109,9 +123,11 @@ public class NetconfClientSessionNegotiator extends
     }
 
     @Override
-    protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfHelloMessage message) throws NetconfDocumentedException {
-        return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()),
-                NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument()));
+    protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel,
+            NetconfHelloMessage message) throws NetconfDocumentedException {
+        long sessionId = extractSessionId(message.getDocument());
+        Collection<String> capabilities = NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument());
+        return new NetconfClientSession(sessionListener, channel, sessionId, capabilities);
     }
 
     /**
@@ -121,9 +137,11 @@ public class NetconfClientSessionNegotiator extends
         private static final String EXI_CONFIRMED_HANDLER = "exiConfirmedHandler";
 
         private final NetconfClientSession session;
+        private NetconfStartExiMessage startExiMessage;
 
-        ExiConfirmationInboundHandler(NetconfClientSession session) {
+        ExiConfirmationInboundHandler(NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
             this.session = session;
+            this.startExiMessage = startExiMessage;
         }
 
         @Override
@@ -136,19 +154,19 @@ public class NetconfClientSessionNegotiator extends
             if (NetconfMessageUtil.isOKMessage(netconfMessage)) {
                 logger.trace("Positive response on start-exi call received on session {}", session);
                 try {
-                    session.startExiCommunication(sessionPreferences.getStartExiMessage());
+                    session.startExiCommunication(startExiMessage);
                 } catch (RuntimeException e) {
                     // Unable to add exi, continue without exi
                     logger.warn("Unable to start exi communication, Communication will continue without exi on session {}", session, e);
                 }
 
-            // Error response
+                // Error response
             } else if(NetconfMessageUtil.isErrorMessage(netconfMessage)) {
                 logger.warn(
                         "Error response to start-exi message {}, Communication will continue without exi on session {}",
                         XmlUtil.toString(netconfMessage.getDocument()), session);
 
-            // Unexpected response to start-exi, throwing message away, continue without exi
+                // Unexpected response to start-exi, throwing message away, continue without exi
             } else {
                 logger.warn(
                         "Unexpected response to start-exi message, should be ok, was {}, " +
@@ -159,4 +177,5 @@ public class NetconfClientSessionNegotiator extends
             negotiationSuccessful(session);
         }
     }
+
 }
index 7af1f01a08ea89c0712b1fb69e80f550832b97cf..e65adc3fdf5b736522592a55e5c81d8fa8f37451 100644 (file)
@@ -74,7 +74,7 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF
             throw new IllegalStateException(e);
         }
 
-        NetconfClientSessionPreferences proposal = new NetconfClientSessionPreferences(helloMessage,startExiMessage);
+        NetconfClientSessionPreferences proposal = new NetconfClientSessionPreferences(helloMessage, startExiMessage);
         return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
                 sessionListenerFactory.getSessionListener(),connectionTimeoutMillis);
     }
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java
deleted file mode 100644 (file)
index 5b82ff2..0000000
+++ /dev/null
@@ -1,120 +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.client;
-
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.Promise;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-
-import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
-import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
-import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
-import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
-import org.opendaylight.protocol.framework.SessionListenerFactory;
-
-import com.google.common.base.Optional;
-
-public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
-
-    private final AuthenticationHandler authHandler;
-    private final HashedWheelTimer timer;
-    private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
-
-    public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
-            EventLoopGroup workerGroup, long connectionTimeoutMillis) {
-        super(bossGroup, workerGroup, connectionTimeoutMillis);
-        this.authHandler = authHandler;
-        this.timer = new HashedWheelTimer();
-        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
-                Optional.<NetconfHelloMessageAdditionalHeader> absent(), connectionTimeoutMillis);
-    }
-
-    public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
-            EventLoopGroup workerGroup, NetconfHelloMessageAdditionalHeader additionalHeader, long socketTimeoutMillis) {
-        super(bossGroup, workerGroup, additionalHeader, socketTimeoutMillis);
-        this.authHandler = authHandler;
-        this.timer = new HashedWheelTimer();
-        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader),
-                socketTimeoutMillis);
-    }
-
-    @Override
-    public Future<NetconfClientSession> createClient(InetSocketAddress address,
-            final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) {
-        return super.createClient(address, strat, new PipelineInitializer<NetconfClientSession>() {
-
-            @Override
-            public void initializeChannel(SocketChannel arg0, Promise<NetconfClientSession> arg1) {
-                new NetconfSshClientInitializer(authHandler, negotiatorFactory, sessionListener).initialize(arg0, arg1);
-            }
-
-        });
-    }
-
-    @Override
-    public Future<Void> createReconnectingClient(final InetSocketAddress address,
-            final NetconfClientSessionListener listener,
-            final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
-        final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotiatorFactory, listener);
-
-        return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
-                new PipelineInitializer<NetconfClientSession>() {
-            @Override
-            public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
-                init.initialize(ch, promise);
-            }
-        });
-    }
-
-    private static final class NetconfSshClientInitializer extends AbstractChannelInitializer<NetconfClientSession> {
-
-        private final AuthenticationHandler authenticationHandler;
-        private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
-        private final NetconfClientSessionListener sessionListener;
-
-        public NetconfSshClientInitializer(AuthenticationHandler authHandler,
-                NetconfClientSessionNegotiatorFactory negotiatorFactory,
-                final NetconfClientSessionListener sessionListener) {
-            this.authenticationHandler = authHandler;
-            this.negotiatorFactory = negotiatorFactory;
-            this.sessionListener = sessionListener;
-        }
-
-        @Override
-        public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
-            try {
-                Invoker invoker = Invoker.subsystem("netconf");
-                ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
-                super.initialize(ch,promise);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        @Override
-        protected void initializeSessionNegotiator(SocketChannel ch,
-                Promise<NetconfClientSession> promise) {
-            ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER,  AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
-                    negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
-                @Override
-                public NetconfClientSessionListener getSessionListener() {
-                    return sessionListener;
-                }
-            }, ch, promise));
-        }
-    }
-}
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java
new file mode 100644 (file)
index 0000000..b86349d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.client;
+
+import io.netty.channel.socket.SocketChannel;
+import io.netty.util.concurrent.Promise;
+import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
+import org.opendaylight.protocol.framework.SessionListenerFactory;
+
+import java.io.IOException;
+
+final class SshClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
+
+    private final AuthenticationHandler authenticationHandler;
+    private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
+    private final NetconfClientSessionListener sessionListener;
+
+    public SshClientChannelInitializer(final AuthenticationHandler authHandler,
+                                       final NetconfClientSessionNegotiatorFactory negotiatorFactory,
+                                       final NetconfClientSessionListener sessionListener) {
+        this.authenticationHandler = authHandler;
+        this.negotiatorFactory = negotiatorFactory;
+        this.sessionListener = sessionListener;
+    }
+
+    @Override
+    public void initialize(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+        try {
+            final Invoker invoker = Invoker.subsystem("netconf");
+            ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
+            super.initialize(ch,promise);
+        } catch (final IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected void initializeSessionNegotiator(final SocketChannel ch,
+                                               final Promise<NetconfClientSession> promise) {
+        ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER,  AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+                negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
+                    @Override
+                    public NetconfClientSessionListener getSessionListener() {
+                        return sessionListener;
+                    }
+                }, ch, promise));
+    }
+}
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/TcpClientChannelInitializer.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/TcpClientChannelInitializer.java
new file mode 100644 (file)
index 0000000..967d3c6
--- /dev/null
@@ -0,0 +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.netconf.client;
+
+import io.netty.channel.socket.SocketChannel;
+import io.netty.util.concurrent.Promise;
+import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.protocol.framework.SessionListenerFactory;
+
+class TcpClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
+
+    private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
+    private final NetconfClientSessionListener sessionListener;
+
+    TcpClientChannelInitializer(final NetconfClientSessionNegotiatorFactory negotiatorFactory,
+                                final NetconfClientSessionListener sessionListener) {
+        this.negotiatorFactory = negotiatorFactory;
+        this.sessionListener = sessionListener;
+    }
+
+    @Override
+    public void initialize(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+        super.initialize(ch, promise);
+    }
+
+    @Override
+    protected void initializeSessionNegotiator(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+        ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+                negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
+                    @Override
+                    public NetconfClientSessionListener getSessionListener() {
+                        return sessionListener;
+                    }
+                }, ch, promise));
+    }
+}
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfClientConfiguration.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfClientConfiguration.java
new file mode 100644 (file)
index 0000000..5a3ec3a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.client.conf;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+
+import java.net.InetSocketAddress;
+
+public class NetconfClientConfiguration {
+
+    private final NetconfClientProtocol clientProtocol;
+    private final InetSocketAddress address;
+    private final Long connectionTimeoutMillis;
+
+    private final NetconfHelloMessageAdditionalHeader additionalHeader;
+    private final NetconfClientSessionListener sessionListener;
+
+    private final ReconnectStrategy reconnectStrategy;
+
+    private final AuthenticationHandler authHandler;
+
+    NetconfClientConfiguration(final NetconfClientProtocol protocol, final InetSocketAddress address, final Long connectionTimeoutMillis, final NetconfHelloMessageAdditionalHeader additionalHeader, final NetconfClientSessionListener sessionListener, final ReconnectStrategy reconnectStrategy, final AuthenticationHandler authHandler) {
+        this.address = address;
+        this.connectionTimeoutMillis = connectionTimeoutMillis;
+        this.additionalHeader = additionalHeader;
+        this.sessionListener = sessionListener;
+        this.clientProtocol = protocol;
+        this.reconnectStrategy = reconnectStrategy;
+        this.authHandler = authHandler;
+        validateConfiguration();
+    }
+
+    public final InetSocketAddress getAddress() {
+        return address;
+    }
+
+    public final Long getConnectionTimeoutMillis() {
+        return connectionTimeoutMillis;
+    }
+
+    public final Optional<NetconfHelloMessageAdditionalHeader> getAdditionalHeader() {
+        return Optional.fromNullable(additionalHeader);
+    }
+
+    public final NetconfClientSessionListener getSessionListener() {
+        return sessionListener;
+    }
+
+    public final ReconnectStrategy getReconnectStrategy() {
+        return reconnectStrategy;
+    }
+
+    public final AuthenticationHandler getAuthHandler() {
+        return authHandler;
+    }
+
+    public NetconfClientProtocol getProtocol() {
+        return clientProtocol;
+    }
+
+    private void validateConfiguration() {
+        Preconditions.checkNotNull(clientProtocol, " ");
+        switch (clientProtocol) {
+        case SSH:
+            validateSshConfiguration();
+            // Fall through intentional (ssh validation is a superset of tcp validation)
+        case TCP:
+            validateTcpConfiguration();
+        }
+    }
+
+    protected void validateSshConfiguration() {
+        Preconditions.checkNotNull(authHandler, "authHandler");
+    }
+
+    protected void validateTcpConfiguration() {
+        Preconditions.checkNotNull(address, "address");
+        Preconditions.checkNotNull(clientProtocol, "clientProtocol");
+        Preconditions.checkNotNull(connectionTimeoutMillis, "connectionTimeoutMillis");
+        Preconditions.checkNotNull(sessionListener, "sessionListener");
+        Preconditions.checkNotNull(reconnectStrategy, "reconnectStrategy");
+    }
+
+    @Override
+    public final String toString() {
+        return buildToStringHelper().toString();
+    }
+
+    protected Objects.ToStringHelper buildToStringHelper() {
+        return Objects.toStringHelper(this)
+                .add("address", address)
+                .add("connectionTimeoutMillis", connectionTimeoutMillis)
+                .add("additionalHeader", additionalHeader)
+                .add("sessionListener", sessionListener)
+                .add("reconnectStrategy", reconnectStrategy)
+                .add("clientProtocol", clientProtocol)
+                .add("authHandler", authHandler);
+    }
+
+    public static enum NetconfClientProtocol {
+        TCP, SSH
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfClientConfigurationBuilder.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfClientConfigurationBuilder.java
new file mode 100644 (file)
index 0000000..a3e57bd
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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.client.conf;
+
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+
+import java.net.InetSocketAddress;
+
+public class NetconfClientConfigurationBuilder {
+
+    public static final int DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000;
+    public static final NetconfClientConfiguration.NetconfClientProtocol DEFAULT_CLIENT_PROTOCOL = NetconfClientConfiguration.NetconfClientProtocol.TCP;
+
+    private InetSocketAddress address;
+    private long connectionTimeoutMillis = DEFAULT_CONNECTION_TIMEOUT_MILLIS;
+    private NetconfHelloMessageAdditionalHeader additionalHeader;
+    private NetconfClientSessionListener sessionListener;
+    private ReconnectStrategy reconnectStrategy;
+    private AuthenticationHandler authHandler;
+    private NetconfClientConfiguration.NetconfClientProtocol clientProtocol = DEFAULT_CLIENT_PROTOCOL;
+
+    protected NetconfClientConfigurationBuilder() {
+    }
+
+    public static NetconfClientConfigurationBuilder create() {
+        return new NetconfClientConfigurationBuilder();
+    }
+
+    public NetconfClientConfigurationBuilder withAddress(final InetSocketAddress address) {
+        this.address = address;
+        return this;
+    }
+
+    public NetconfClientConfigurationBuilder withConnectionTimeoutMillis(final long connectionTimeoutMillis) {
+        this.connectionTimeoutMillis = connectionTimeoutMillis;
+        return this;
+    }
+
+    public NetconfClientConfigurationBuilder withProtocol(final NetconfClientConfiguration.NetconfClientProtocol clientProtocol) {
+        this.clientProtocol = clientProtocol;
+        return this;
+    }
+
+    public NetconfClientConfigurationBuilder withAdditionalHeader(final NetconfHelloMessageAdditionalHeader additionalHeader) {
+        this.additionalHeader = additionalHeader;
+        return this;
+    }
+
+    public NetconfClientConfigurationBuilder withSessionListener(final NetconfClientSessionListener sessionListener) {
+        this.sessionListener = sessionListener;
+        return this;
+    }
+
+    public NetconfClientConfigurationBuilder withReconnectStrategy(final ReconnectStrategy reconnectStrategy) {
+        this.reconnectStrategy = reconnectStrategy;
+        return this;
+    }
+
+    public NetconfClientConfigurationBuilder withAuthHandler(final AuthenticationHandler authHandler) {
+        this.authHandler = authHandler;
+        return this;
+    }
+
+    final InetSocketAddress getAddress() {
+        return address;
+    }
+
+    final long getConnectionTimeoutMillis() {
+        return connectionTimeoutMillis;
+    }
+
+    final NetconfHelloMessageAdditionalHeader getAdditionalHeader() {
+        return additionalHeader;
+    }
+
+    final NetconfClientSessionListener getSessionListener() {
+        return sessionListener;
+    }
+
+    final ReconnectStrategy getReconnectStrategy() {
+        return reconnectStrategy;
+    }
+
+    final AuthenticationHandler getAuthHandler() {
+        return authHandler;
+    }
+
+    final NetconfClientConfiguration.NetconfClientProtocol getProtocol() {
+        return clientProtocol;
+    }
+
+    public NetconfClientConfiguration build() {
+        return new NetconfClientConfiguration(clientProtocol, address, connectionTimeoutMillis, additionalHeader, sessionListener, reconnectStrategy, authHandler);
+    }
+}
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfReconnectingClientConfiguration.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfReconnectingClientConfiguration.java
new file mode 100644 (file)
index 0000000..64fcc48
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.client.conf;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+
+import java.net.InetSocketAddress;
+
+public final class NetconfReconnectingClientConfiguration extends NetconfClientConfiguration {
+
+    private final ReconnectStrategyFactory connectStrategyFactory;
+
+    NetconfReconnectingClientConfiguration(final NetconfClientProtocol clientProtocol, final InetSocketAddress address,
+            final Long connectionTimeoutMillis, final NetconfHelloMessageAdditionalHeader additionalHeader,
+            final NetconfClientSessionListener sessionListener, final ReconnectStrategy reconnectStrategy,
+            final ReconnectStrategyFactory connectStrategyFactory, final AuthenticationHandler authHandler) {
+        super(clientProtocol, address, connectionTimeoutMillis, additionalHeader, sessionListener, reconnectStrategy,
+                authHandler);
+        this.connectStrategyFactory = connectStrategyFactory;
+        validateReconnectConfiguration();
+    }
+
+    public ReconnectStrategyFactory getConnectStrategyFactory() {
+        return connectStrategyFactory;
+    }
+
+    private void validateReconnectConfiguration() {
+        Preconditions.checkNotNull(connectStrategyFactory);
+    }
+
+    @Override
+    protected Objects.ToStringHelper buildToStringHelper() {
+        return super.buildToStringHelper().add("connectStrategyFactory", connectStrategyFactory);
+    }
+}
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java
new file mode 100644 (file)
index 0000000..411ac3c
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.client.conf;
+
+import java.net.InetSocketAddress;
+
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
+
+public class NetconfReconnectingClientConfigurationBuilder extends NetconfClientConfigurationBuilder {
+
+    private ReconnectStrategyFactory connectStrategyFactory;
+
+    private NetconfReconnectingClientConfigurationBuilder() {
+    }
+
+    public static NetconfReconnectingClientConfigurationBuilder create() {
+        return new NetconfReconnectingClientConfigurationBuilder();
+    }
+
+
+    public NetconfReconnectingClientConfigurationBuilder withConnectStrategyFactory(final ReconnectStrategyFactory connectStrategyFactory) {
+        this.connectStrategyFactory = connectStrategyFactory;
+        return this;
+    }
+
+    @Override
+    public NetconfReconnectingClientConfiguration build() {
+        return new NetconfReconnectingClientConfiguration(getProtocol(), getAddress(), getConnectionTimeoutMillis(), getAdditionalHeader(), getSessionListener(), getReconnectStrategy(), connectStrategyFactory, getAuthHandler());
+    }
+
+    // Override setter methods to return subtype
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withAddress(final InetSocketAddress address) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withAddress(address);
+    }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withConnectionTimeoutMillis(final long connectionTimeoutMillis) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withConnectionTimeoutMillis(connectionTimeoutMillis);
+    }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withAdditionalHeader(final NetconfHelloMessageAdditionalHeader additionalHeader) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withAdditionalHeader(additionalHeader);
+    }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withSessionListener(final NetconfClientSessionListener sessionListener) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withSessionListener(sessionListener);
+    }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withReconnectStrategy(final ReconnectStrategy reconnectStrategy) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withReconnectStrategy(reconnectStrategy);
+    }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withAuthHandler(final AuthenticationHandler authHandler) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withAuthHandler(authHandler);
+    }
+
+    @Override
+    public NetconfReconnectingClientConfigurationBuilder withProtocol(NetconfClientConfiguration.NetconfClientProtocol clientProtocol) {
+        return (NetconfReconnectingClientConfigurationBuilder) super.withProtocol(clientProtocol);
+    }
+}
index 32c6ea85d69ffdd112afdd0cf103d3be7ac58247..60d8f3044aee5667ea04858377d31b109ca88ef0 100644 (file)
@@ -8,12 +8,8 @@
 
 package org.opendaylight.controller.netconf.client.test;
 
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
 import java.io.Closeable;
 import java.io.IOException;
-import java.net.InetSocketAddress;
 import java.util.Set;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
@@ -25,11 +21,11 @@ import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.NetconfClientSession;
 import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
+import io.netty.util.concurrent.Future;
 
 
 /**
@@ -44,11 +40,11 @@ public class TestingNetconfClient implements Closeable {
     private final NetconfClientSessionListener sessionListener;
     private final long sessionId;
 
-    private TestingNetconfClient(String clientLabel, InetSocketAddress address, ReconnectStrategy strat,
-            NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+    public TestingNetconfClient(String clientLabel,
+                                 NetconfClientDispatcher netconfClientDispatcher, final NetconfClientConfiguration config) throws InterruptedException {
         this.label = clientLabel;
-        sessionListener = new SimpleNetconfClientSessionListener();
-        Future<NetconfClientSession> clientFuture = netconfClientDispatcher.createClient(address, sessionListener, strat);
+        sessionListener = config.getSessionListener();
+        Future<NetconfClientSession> clientFuture = netconfClientDispatcher.createClient(config);
         clientSession = get(clientFuture);
         this.sessionId = clientSession.getSessionId();
     }
@@ -63,18 +59,6 @@ public class TestingNetconfClient implements Closeable {
         }
     }
 
-    public TestingNetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
-                                NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        this(clientLabelForLogging, address,
-                new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), netconfClientDispatcher);
-    }
-
-    public TestingNetconfClient(String clientLabelForLogging, InetSocketAddress address,
-                                NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
-                DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
-    }
-
     public Future<NetconfMessage> sendRequest(NetconfMessage message) {
         return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
     }
@@ -111,4 +95,4 @@ public class TestingNetconfClient implements Closeable {
         Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
         return Sets.newHashSet(clientSession.getServerCapabilities());
     }
-}
\ No newline at end of file
+}
index 5c389fa966af340ef277f5d51ebe992b2c6081ff..6528fe251775694e8ea47cf59b094d0efcc07ddf 100644 (file)
@@ -8,10 +8,9 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Optional;
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
+import java.net.InetSocketAddress;
+
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
@@ -19,7 +18,11 @@ import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAddi
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
+
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
 
 public class NetconfServerSessionNegotiator extends
         AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession, NetconfServerSessionListener> {
@@ -32,6 +35,14 @@ public class NetconfServerSessionNegotiator extends
         super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
 
+    @Override
+    protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
+        NetconfServerSession session = getSessionForHelloMessage(netconfMessage);
+        replaceHelloMessageInboundHandler(session);
+        // Negotiation successful after all non hello messages were processed
+        negotiationSuccessful(session);
+    }
+
     @Override
     protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfHelloMessage message) {
         Optional<NetconfHelloMessageAdditionalHeader> additionalHeader = message.getAdditionalHeader();
index c5f8e99f2271baaa84b9a4c58657a69f50c92369..d5a34d11b244681b1540ff95bae22b26ba607670 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.impl;
 
 import static org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider.NetconfOperationProviderUtil.getNetconfSessionIdForReporting;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import java.util.Set;
 
@@ -35,12 +36,10 @@ import org.slf4j.LoggerFactory;
 
 public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfHelloMessage, NetconfServerSession, NetconfServerSessionListener> {
 
-    private static final Set<String> DEFAULT_BASE_CAPABILITIES = ImmutableSet.of(
-            XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0
-            // FIXME, Chunk framing causes ConcurrentClientsTest to fail, investigate
-//            XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1,
-            // FIXME, EXI causing issues with sal-netconf-connector, investigate
-//            XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0
+    public static final Set<String> DEFAULT_BASE_CAPABILITIES = ImmutableSet.of(
+            XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
+            XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1,
+            XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0
     );
 
     private final Timer timer;
@@ -51,18 +50,42 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     private final DefaultCommitNotificationProducer commitNotificationProducer;
     private final SessionMonitoringService monitoringService;
     private static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiatorFactory.class);
+    private final Set<String> baseCapabilities;
 
     // TODO too many params, refactor
     public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
                                                  SessionIdProvider idProvider, long connectionTimeoutMillis,
                                                  DefaultCommitNotificationProducer commitNot,
                                                  SessionMonitoringService monitoringService) {
+        this(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, commitNot, monitoringService, DEFAULT_BASE_CAPABILITIES);
+    }
+
+    // TODO too many params, refactor
+    public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
+                                                 SessionIdProvider idProvider, long connectionTimeoutMillis,
+                                                 DefaultCommitNotificationProducer commitNot,
+                                                 SessionMonitoringService monitoringService, Set<String> baseCapabilities) {
         this.timer = timer;
         this.netconfOperationProvider = netconfOperationProvider;
         this.idProvider = idProvider;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
         this.commitNotificationProducer = commitNot;
         this.monitoringService = monitoringService;
+        this.baseCapabilities = validateBaseCapabilities(baseCapabilities);
+    }
+
+    private ImmutableSet<String> validateBaseCapabilities(final Set<String> baseCapabilities) {
+        // Check base capabilities to be supported by the server
+        Sets.SetView<String> unknownBaseCaps = Sets.difference(baseCapabilities, DEFAULT_BASE_CAPABILITIES);
+        Preconditions.checkArgument(unknownBaseCaps.isEmpty(),
+                "Base capabilities that will be supported by netconf server have to be subset of %s, unknown base capabilities: %s",
+                DEFAULT_BASE_CAPABILITIES, unknownBaseCaps);
+
+        ImmutableSet.Builder<String> b = ImmutableSet.builder();
+        b.addAll(baseCapabilities);
+        // Base 1.0 capability is supported by default
+        b.add(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0);
+        return b.build();
     }
 
     /**
@@ -100,7 +123,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     }
 
     private NetconfHelloMessage createHelloMessage(long sessionId, CapabilityProvider capabilityProvider) throws NetconfDocumentedException {
-        return NetconfHelloMessage.createServerHello(Sets.union(capabilityProvider.getCapabilities(), DEFAULT_BASE_CAPABILITIES), sessionId);
+        return NetconfHelloMessage.createServerHello(Sets.union(capabilityProvider.getCapabilities(), baseCapabilities), sessionId);
     }
 
 }
index 02889b62a5bf71fe6cdb1161c7ac3fdaa0c00eaf..b8622d1e911c54e225fb02bc032c5a9f9fae702a 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.netconf.impl;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doNothing;
@@ -20,18 +21,33 @@ import java.io.InputStreamReader;
 import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
 import java.net.Socket;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
@@ -42,37 +58,67 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedEx
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
 import org.opendaylight.controller.netconf.util.messages.NetconfStartExiMessage;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.GlobalEventExecutor;
 
+@RunWith(Parameterized.class)
 public class ConcurrentClientsTest {
+    private static final Logger logger = LoggerFactory.getLogger(ConcurrentClientsTest.class);
 
-    private static final int CONCURRENCY = 16;
-    private EventLoopGroup nettyGroup;
-    private NetconfClientDispatcher netconfClientDispatcher;
+    private static ExecutorService clientExecutor;
 
-    private final InetSocketAddress netconfAddress = new InetSocketAddress("127.0.0.1", 8303);
+    private static final int CONCURRENCY = 32;
+    private static final InetSocketAddress netconfAddress = new InetSocketAddress("127.0.0.1", 8303);
 
-    static final Logger logger = LoggerFactory.getLogger(ConcurrentClientsTest.class);
+    private int nettyThreads;
+    private Class<? extends Runnable> clientRunnable;
+    private Set<String> serverCaps;
 
-    private DefaultCommitNotificationProducer commitNot;
-    private NetconfServerDispatcher dispatch;
+    public ConcurrentClientsTest(int nettyThreads, Class<? extends Runnable> clientRunnable, Set<String> serverCaps) {
+        this.nettyThreads = nettyThreads;
+        this.clientRunnable = clientRunnable;
+        this.serverCaps = serverCaps;
+    }
 
+    @Parameterized.Parameters()
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {4, TestingNetconfClientRunnable.class, NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES},
+                {1, TestingNetconfClientRunnable.class, NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES},
+                // empty set of capabilities = only base 1.0 netconf capability
+                {4, TestingNetconfClientRunnable.class, Collections.emptySet()},
+                {4, TestingNetconfClientRunnable.class, getOnlyExiServerCaps()},
+                {4, TestingNetconfClientRunnable.class, getOnlyChunkServerCaps()},
+
+                {4, BlockingClientRunnable.class, getOnlyExiServerCaps()},
+                {1, BlockingClientRunnable.class, getOnlyExiServerCaps()},
+        });
+    }
 
+    private EventLoopGroup nettyGroup;
+    private NetconfClientDispatcher netconfClientDispatcher;
+
+    private DefaultCommitNotificationProducer commitNot;
 
     HashedWheelTimer hashedWheelTimer;
+    private TestingNetconfOperation testingNetconfOperation;
 
     public static SessionMonitoringService createMockedMonitoringService() {
         SessionMonitoringService monitoring = mock(SessionMonitoringService.class);
@@ -81,26 +127,41 @@ public class ConcurrentClientsTest {
         return monitoring;
     }
 
+    @BeforeClass
+    public static void setUpClientExecutor() {
+        clientExecutor = Executors.newFixedThreadPool(CONCURRENCY, new ThreadFactory() {
+            int i = 1;
+
+            @Override
+            public Thread newThread(final Runnable r) {
+                Thread thread = new Thread(r);
+                thread.setName("client-" + i++);
+                thread.setDaemon(true);
+                return thread;
+            }
+        });
+    }
+
     @Before
     public void setUp() throws Exception {
-
-        nettyGroup = new NioEventLoopGroup();
-        NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client");
-        netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, additionalHeader, 5000);
+        hashedWheelTimer = new HashedWheelTimer();
+        nettyGroup = new NioEventLoopGroup(nettyThreads);
+        netconfClientDispatcher = new NetconfClientDispatcherImpl(nettyGroup, nettyGroup, hashedWheelTimer);
 
         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
-        factoriesListener.onAddNetconfOperationServiceFactory(mockOpF());
+
+        testingNetconfOperation = new TestingNetconfOperation();
+        factoriesListener.onAddNetconfOperationServiceFactory(new TestingOperationServiceFactory(testingNetconfOperation));
 
         SessionIdProvider idProvider = new SessionIdProvider();
-        hashedWheelTimer = new HashedWheelTimer();
 
         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, createMockedMonitoringService());
+                hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, createMockedMonitoringService(), serverCaps);
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
         NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory);
-        dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
+        final NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
 
         ChannelFuture s = dispatch.createServer(netconfAddress);
         s.await();
@@ -108,113 +169,131 @@ public class ConcurrentClientsTest {
 
     @After
     public void tearDown(){
+        commitNot.close();
         hashedWheelTimer.stop();
-        nettyGroup.shutdownGracefully();
+        try {
+            nettyGroup.shutdownGracefully().get();
+        } catch (InterruptedException | ExecutionException e) {
+            logger.warn("Ignoring exception while cleaning up after test", e);
+        }
     }
 
-    private NetconfOperationServiceFactory mockOpF() {
-        return new NetconfOperationServiceFactory() {
-            @Override
-            public NetconfOperationService createService(String netconfSessionIdForReporting) {
-                return new NetconfOperationService() {
-                    @Override
-                    public Set<Capability> getCapabilities() {
-                        return Collections.emptySet();
-                    }
-
-                    @Override
-                    public Set<NetconfOperation> getNetconfOperations() {
-                        return Sets.<NetconfOperation> newHashSet(new NetconfOperation() {
-                            @Override
-                            public HandlingPriority canHandle(Document message) {
-                                return XmlUtil.toString(message).contains(NetconfStartExiMessage.START_EXI) ?
-                                        HandlingPriority.CANNOT_HANDLE :
-                                        HandlingPriority.HANDLE_WITH_MAX_PRIORITY;
-                            }
-
-                            @Override
-                            public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
-                                try {
-                                    return XmlUtil.readXmlToDocument("<test/>");
-                                } catch (Exception e) {
-                                    throw new RuntimeException(e);
-                                }
-                            }
-                        });
-                    }
-
-                    @Override
-                    public void close() {
-                    }
-                };
-            }
-        };
+    @AfterClass
+    public static void tearDownClientExecutor() {
+        clientExecutor.shutdownNow();
     }
 
-    @After
-    public void cleanUp() throws Exception {
-        commitNot.close();
-    }
+    @Test(timeout = CONCURRENCY * 1000)
+    public void testConcurrentClients() throws Exception {
 
-    @Test(timeout = 30 * 1000)
-    public void multipleClients() throws Exception {
-        List<TestingThread> threads = new ArrayList<>();
+        List<Future<?>> futures = Lists.newArrayListWithCapacity(CONCURRENCY);
 
-        final int attempts = 5;
         for (int i = 0; i < CONCURRENCY; i++) {
-            TestingThread thread = new TestingThread(String.valueOf(i), attempts);
-            threads.add(thread);
-            thread.start();
+            futures.add(clientExecutor.submit(getInstanceOfClientRunnable()));
         }
 
-        for (TestingThread thread : threads) {
-            thread.join();
-            if(thread.thrownException.isPresent()) {
-                Exception exception = thread.thrownException.get();
-                logger.error("Thread for testing client failed", exception);
-                fail("Client thread " + thread + " failed: " + exception.getMessage());
+        for (Future<?> future : futures) {
+            try {
+                future.get();
+            } catch (InterruptedException e) {
+                throw new IllegalStateException(e);
+            } catch (ExecutionException e) {
+                logger.error("Thread for testing client failed", e);
+                fail("Client failed: " + e.getMessage());
             }
         }
+
+        assertEquals(CONCURRENCY, testingNetconfOperation.getMessageCount());
     }
 
-    @Test(timeout = 30 * 1000)
-    public void synchronizationTest() throws Exception {
-        new BlockingThread("foo").run2();
+    public static Set<String> getOnlyExiServerCaps() {
+        return Sets.newHashSet(
+                XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
+                XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0
+        );
     }
 
-    @Test(timeout = 30 * 1000)
-    public void multipleBlockingClients() throws Exception {
-        List<BlockingThread> threads = new ArrayList<>();
-        for (int i = 0; i < CONCURRENCY; i++) {
-            BlockingThread thread = new BlockingThread(String.valueOf(i));
-            threads.add(thread);
-            thread.start();
+    public static Set<String> getOnlyChunkServerCaps() {
+        return Sets.newHashSet(
+                XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
+                XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1
+        );
+    }
+
+    public Runnable getInstanceOfClientRunnable() throws Exception {
+        return clientRunnable.getConstructor(ConcurrentClientsTest.class).newInstance(this);
+    }
+
+    /**
+     * Responds to all operations except start-exi and counts all requests
+     */
+    private static class TestingNetconfOperation implements NetconfOperation {
+
+        private final AtomicLong counter = new AtomicLong();
+
+        @Override
+        public HandlingPriority canHandle(Document message) {
+            return XmlUtil.toString(message).contains(NetconfStartExiMessage.START_EXI) ?
+                    HandlingPriority.CANNOT_HANDLE :
+                    HandlingPriority.HANDLE_WITH_MAX_PRIORITY;
         }
 
-        for (BlockingThread thread : threads) {
-            thread.join();
-            if(thread.thrownException.isPresent()) {
-                Exception exception = thread.thrownException.get();
-                logger.error("Thread for testing client failed", exception);
-                fail("Client thread " + thread + " failed: " + exception.getMessage());
+        @Override
+        public Document handle(Document requestMessage, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
+            try {
+                logger.info("Handling netconf message from test {}", XmlUtil.toString(requestMessage));
+                counter.getAndIncrement();
+                return XmlUtil.readXmlToDocument("<test/>");
+            } catch (Exception e) {
+                throw new RuntimeException(e);
             }
         }
+
+        public long getMessageCount() {
+            return counter.get();
+        }
     }
 
-    class BlockingThread extends Thread {
-        private Optional<Exception> thrownException;
+    /**
+     * Hardcoded operation service factory
+     */
+    private static class TestingOperationServiceFactory implements NetconfOperationServiceFactory {
+        private final NetconfOperation[] operations;
 
-        public BlockingThread(String name) {
-            super("client-" + name);
+        public TestingOperationServiceFactory(final NetconfOperation... operations) {
+            this.operations = operations;
         }
 
+        @Override
+        public NetconfOperationService createService(String netconfSessionIdForReporting) {
+            return new NetconfOperationService() {
+                @Override
+                public Set<Capability> getCapabilities() {
+                    return Collections.emptySet();
+                }
+
+                @Override
+                public Set<NetconfOperation> getNetconfOperations() {
+                    return Sets.newHashSet(operations);
+                }
+
+                @Override
+                public void close() {}
+            };
+        }
+    }
+
+    /**
+     * Pure socket based blocking client
+     */
+    public final class BlockingClientRunnable implements Runnable {
+
         @Override
         public void run() {
             try {
                 run2();
-                thrownException = Optional.absent();
             } catch (Exception e) {
-                thrownException = Optional.of(e);
+                throw new IllegalStateException(Thread.currentThread().getName(), e);
             }
         }
 
@@ -250,35 +329,44 @@ public class ConcurrentClientsTest {
         }
     }
 
-    class TestingThread extends Thread {
-
-        private final String clientId;
-        private final int attempts;
-        private Optional<Exception> thrownException;
-
-        TestingThread(String clientId, int attempts) {
-            this.clientId = clientId;
-            this.attempts = attempts;
-            setName("client-" + clientId);
-        }
+    /**
+     * TestingNetconfClient based runnable
+     */
+    public final class TestingNetconfClientRunnable implements Runnable {
 
         @Override
         public void run() {
             try {
-                final TestingNetconfClient netconfClient = new TestingNetconfClient(clientId, netconfAddress, netconfClientDispatcher);
+                final TestingNetconfClient netconfClient =
+                        new TestingNetconfClient(Thread.currentThread().getName(), netconfClientDispatcher, getClientConfig());
                 long sessionId = netconfClient.getSessionId();
-                logger.info("Client with sessionid {} hello exchanged", sessionId);
+                logger.info("Client with session id {}: hello exchanged", sessionId);
 
                 final NetconfMessage getMessage = XmlFileLoader
                         .xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
                 NetconfMessage result = netconfClient.sendRequest(getMessage).get();
-                logger.info("Client with sessionid {} got result {}", sessionId, result);
+                logger.info("Client with session id {}: got result {}", sessionId, result);
+
+                Preconditions.checkState(NetconfMessageUtil.isErrorMessage(result) == false,
+                        "Received error response: " + XmlUtil.toString(result.getDocument()) + " to request: "
+                                + XmlUtil.toString(getMessage.getDocument()));
+
                 netconfClient.close();
-                logger.info("Client with session id {} ended", sessionId);
-                thrownException = Optional.absent();
+                logger.info("Client with session id {}: ended", sessionId);
             } catch (final Exception e) {
-                thrownException = Optional.of(e);
+                throw new IllegalStateException(Thread.currentThread().getName(), e);
             }
         }
+
+        private NetconfClientConfiguration getClientConfig() {
+            final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+            b.withAddress(netconfAddress);
+            b.withAdditionalHeader(new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp",
+                    "client"));
+            b.withSessionListener(new SimpleNetconfClientSessionListener());
+            b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
+                    NetconfClientConfigurationBuilder.DEFAULT_CONNECTION_TIMEOUT_MILLIS));
+            return b.build();
+        }
     }
 }
index b330f9bcd4f05b915e76caf878dc0fa25e6489e2..ce5203232035413c997ef54b4523becb189f3046 100644 (file)
   </properties>
 
   <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>sal-binding-it</artifactId>
+      <exclusions>
+        <!-- FIXME see IdentityRefNetconfTest  -->
+        <!-- Pax-url-aether contains guava classes e.g. ImmutableSet that clashes with guava and causes tests to fail-->
+        <exclusion>
+          <groupId>org.ops4j.pax.url</groupId>
+          <artifactId>pax-url-aether</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>commons.logback_settings</artifactId>
       <artifactId>netty-config-api</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>sal-binding-it</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>yang-test</artifactId>
           <forkCount>1</forkCount>
           <reuseForks>false</reuseForks>
           <perCoreThreadCount>false</perCoreThreadCount>
+          <classpathDependencyExcludes>
+            <classpathDependencyExcludes>com.google.collections:google-collections</classpathDependencyExcludes>
+            <classpathDependencyExcludes>org.ops4j.pax.url:pax-url-aether</classpathDependencyExcludes>
+          </classpathDependencyExcludes>
         </configuration>
         <executions>
           <execution>
index b81f950cb362cf8f810201bfe98c983e1bf0988d..d4073e5c178f1748ef71ee8466e70982646dab94 100644 (file)
@@ -7,22 +7,30 @@
  */
 package org.opendaylight.controller.netconf.it;
 
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.HashedWheelTimer;
+import java.net.InetSocketAddress;
+
 import org.junit.After;
 import org.junit.Before;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.GlobalEventExecutor;
 
 public class AbstractNetconfConfigTest extends AbstractConfigTest {
 
-    protected EventLoopGroup nettyThreadgroup;
+    private EventLoopGroup nettyThreadgroup;
     private HashedWheelTimer hashedWheelTimer;
 
     @Before
@@ -31,7 +39,6 @@ public class AbstractNetconfConfigTest extends AbstractConfigTest {
         hashedWheelTimer = new HashedWheelTimer();
     }
 
-
     protected NetconfServerDispatcher createDispatcher(
             NetconfOperationServiceFactoryListenerImpl factoriesListener, SessionMonitoringService sessionMonitoringService,
             DefaultCommitNotificationProducer commitNotifier) {
@@ -45,6 +52,13 @@ public class AbstractNetconfConfigTest extends AbstractConfigTest {
         return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
     }
 
+    protected HashedWheelTimer getHashedWheelTimer() {
+        return hashedWheelTimer;
+    }
+
+    protected EventLoopGroup getNettyThreadgroup() {
+        return nettyThreadgroup;
+    }
 
     @After
     public void cleanUpTimer() {
@@ -52,4 +66,13 @@ public class AbstractNetconfConfigTest extends AbstractConfigTest {
         nettyThreadgroup.shutdownGracefully();
     }
 
+    public NetconfClientConfiguration getClientConfiguration(final InetSocketAddress tcpAddress, final int timeout) {
+        final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+        b.withAddress(tcpAddress);
+        b.withSessionListener(new SimpleNetconfClientSessionListener());
+        b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
+                timeout));
+        b.withConnectionTimeoutMillis(timeout);
+        return b.build();
+    }
 }
index d7f77148e812f98cf466f1250ee49d82aee2cb71..3fa1b0195a4a95c0acda2a04edbe7a556c7dfb58 100644 (file)
@@ -7,14 +7,7 @@
  */
 package org.opendaylight.controller.netconf.it;
 
-import org.apache.commons.io.IOUtils;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import static org.junit.Assert.assertNotNull;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -24,7 +17,14 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 
-import static org.junit.Assert.assertNotNull;
+import org.apache.commons.io.IOUtils;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 
 public class HardcodedYangStoreService implements YangStoreService {
 
index af83fe46027ee6816855ab1a6e051139fea5603d..29afa93d373cb5e7a7b86c57b0f93b6cceeeb48e 100644 (file)
@@ -17,7 +17,6 @@ import static org.mockito.Mockito.mock;
 import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithName;
 import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertElementsCount;
 import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToDocument;
-import io.netty.channel.ChannelFuture;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -43,6 +42,7 @@ import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
@@ -65,16 +65,14 @@ import org.xml.sax.SAXException;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
 
 public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
 
     private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
 
-
-
     private NetconfClientDispatcher clientDispatcher;
-
-    DefaultCommitNotificationProducer commitNotifier;
+    private DefaultCommitNotificationProducer commitNotifier;
 
     @Before
     public void setUp() throws Exception {
@@ -95,7 +93,7 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
         ChannelFuture s = dispatch.createServer(tcpAddress);
         s.await();
 
-        clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
+        clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
     }
 
     @After
@@ -124,12 +122,12 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
         VerifyingNotificationListener notificationVerifier = createCommitNotificationListener();
         VerifyingPersister mockedAggregator = mockAggregator();
 
-        try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", tcpAddress, 4000, clientDispatcher)) {
+        try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
             try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(
                     platformMBeanServer, mockedAggregator)) {
 
 
-                try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
+                try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
                     NetconfMessage response = netconfClient.sendMessage(loadGetConfigMessage());
                     assertContainsElementWithName(response.getDocument(), "modules");
                     assertContainsElementWithName(response.getDocument(), "services");
index cc9e8c367a9f3d2871842510daddd29aa95ea441..4dc4b707d4708253579e8135ddd1b6c1e95af1c9 100644 (file)
@@ -8,45 +8,71 @@
 
 package org.opendaylight.controller.netconf.it;
 
-import io.netty.channel.ChannelFuture;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.util.Collection;
+import java.util.List;
+
+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;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.util.Collection;
-import java.util.List;
+import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
+import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+
+import ch.ethz.ssh2.Connection;
+import io.netty.channel.ChannelFuture;
+import io.netty.util.concurrent.GlobalEventExecutor;
 
 public class NetconfITSecureTest extends AbstractNetconfConfigTest {
 
     private static final InetSocketAddress tlsAddress = new InetSocketAddress("127.0.0.1", 12024);
+    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
 
     private DefaultCommitNotificationProducer commitNot;
-    private NetconfServerDispatcher dispatchS;
-
+    private NetconfSSHServer sshServer;
+    private NetconfMessage getConfig;
 
     @Before
     public void setUp() throws Exception {
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,getModuleFactories().toArray(
+        this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, getModuleFactories().toArray(
                 new ModuleFactory[0])));
 
         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
@@ -55,9 +81,14 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
 
-        dispatchS = createDispatcher(factoriesListener);
-        ChannelFuture s = dispatchS.createServer(tlsAddress);
+        final NetconfServerDispatcher dispatchS = createDispatcher(factoriesListener);
+        ChannelFuture s = dispatchS.createServer(tcpAddress);
         s.await();
+
+        sshServer = NetconfSSHServer.start(tlsAddress.getPort(), tcpAddress, getAuthProvider());
+        Thread thread = new Thread(sshServer);
+        thread.setDaemon(true);
+        thread.start();
     }
 
     private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
@@ -66,19 +97,10 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
 
     @After
     public void tearDown() throws Exception {
+        sshServer.stop();
         commitNot.close();
     }
 
-    private SSLContext getSslContext() throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
-            IOException, UnrecoverableKeyException, KeyManagementException {
-        final InputStream keyStore = getClass().getResourceAsStream("/keystore.jks");
-        final InputStream trustStore = getClass().getResourceAsStream("/keystore.jks");
-        SSLContext sslContext = SSLUtil.initializeSecureContext("password", keyStore, trustStore, KeyManagerFactory.getDefaultAlgorithm());
-        keyStore.close();
-        trustStore.close();
-        return sslContext;
-    }
-
     private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
         final Collection<InputStream> yangDependencies = NetconfITTest.getBasicYangs();
         return new HardcodedYangStoreService(yangDependencies);
@@ -90,9 +112,57 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testSecure() throws Exception {
-        NetconfClientDispatcher dispatch = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("tls-client", tlsAddress, 4000, dispatch))  {
-
+        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" +
+                    "     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" +
+                    "    </get-schema>\n" +
+                    "</rpc>\n"));
+
+            response = netconfClient.sendMessage(gs);
+            Assert.assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
+                    NetconfMessageUtil.isErrorMessage(response));
         }
     }
+
+    public NetconfClientConfiguration getClientConfiguration() throws IOException {
+        final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+        b.withAddress(tlsAddress);
+        b.withSessionListener(new SimpleNetconfClientSessionListener());
+        b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000));
+        b.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH);
+        b.withConnectionTimeoutMillis(5000);
+        b.withAuthHandler(getAuthHandler());
+        return b.build();
+    }
+
+    public AuthProvider getAuthProvider() throws Exception {
+        final IUserManager userManager = mock(IUserManager.class);
+        doReturn(AuthResultEnum.AUTH_ACCEPT).when(userManager).authenticate(anyString(), anyString());
+
+        final File privateKeyFile = Files.createTempFile("tmp-netconf-test", "pk").toFile();
+        privateKeyFile.deleteOnExit();
+        String privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
+        return new AuthProvider(userManager, privateKeyPEMString);
+    }
+
+    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;
+    }
 }
index 857cc3e2e5f2d52e411f2526a5561be94e481a35..e99e51e92f67c14e28c06a7b52dc65b64894ac28 100644 (file)
@@ -8,12 +8,32 @@
 
 package org.opendaylight.controller.netconf.it;
 
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
+import static java.util.Collections.emptyList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
 import junit.framework.Assert;
+
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
 import org.junit.Before;
@@ -29,7 +49,7 @@ import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
 import org.opendaylight.controller.netconf.StubUserManager;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
@@ -53,28 +73,12 @@ import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
 
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
 
-import static java.util.Collections.emptyList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
 
 public class NetconfITTest extends AbstractNetconfConfigTest {
 
@@ -92,7 +96,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     private DefaultCommitNotificationProducer commitNot;
     private NetconfServerDispatcher dispatch;
 
-    private NetconfClientDispatcher clientDispatcher;
+    private NetconfClientDispatcherImpl clientDispatcher;
 
     @Before
     public void setUp() throws Exception {
@@ -111,7 +115,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         ChannelFuture s = dispatch.createServer(tcpAddress);
         s.await();
 
-        clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
+        clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
     }
 
     private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
@@ -178,7 +182,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testNetconfClientDemonstration() throws Exception {
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
 
             Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
             long sessionId = netconfClient.getSessionId();
@@ -193,8 +197,8 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testTwoSessions() throws Exception {
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", tcpAddress, 10000, clientDispatcher))  {
-            try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", tcpAddress, 10000, clientDispatcher)) {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", clientDispatcher, getClientConfiguration(tcpAddress, 10000)))  {
+            try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) {
             }
         }
     }
@@ -367,7 +371,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     }
 
     private TestingNetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
-        final TestingNetconfClient netconfClient = new TestingNetconfClient("test " + address.toString(), address, 5000, clientDispatcher);
+        final TestingNetconfClient netconfClient = new TestingNetconfClient("test " + address.toString(), clientDispatcher, getClientConfiguration(address, 5000));
         assertEquals(expected, Long.toString(netconfClient.getSessionId()));
         return netconfClient;
     }
@@ -411,7 +415,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
                     try {
                         c = sess.getStdout().read(bytes);
                     } catch (IOException e) {
-                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+                        throw new IllegalStateException("IO exception while reading data on ssh bridge.");
                     }
                     logger.info("got data:" + bytes);
                     if (c == 0) {
index 8e98ab6320c65d28e0dd1ab29ed5f37f2e31b14b..3b263f7e75cc826b55b893a76a1f5fbf4b051c34 100644 (file)
@@ -7,11 +7,24 @@
  */
 package org.opendaylight.controller.netconf.it;
 
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
 import junit.framework.Assert;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -19,7 +32,7 @@ import org.opendaylight.controller.config.manager.impl.factoriesresolver.Hardcod
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
@@ -40,21 +53,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelFuture;
 
 public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
 
@@ -66,7 +68,7 @@ public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
     private DefaultCommitNotificationProducer commitNot;
     private NetconfServerDispatcher dispatch;
 
-    private NetconfClientDispatcher clientDispatcher;
+    private NetconfClientDispatcherImpl clientDispatcher;
 
     private NetconfMonitoringServiceImpl monitoringService;
 
@@ -88,7 +90,7 @@ public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
         ChannelFuture s = dispatch.createServer(tcpAddress);
         s.await();
 
-        clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
+        clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
     }
 
     private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
@@ -120,8 +122,8 @@ public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testGetResponseFromMonitoring() throws Exception {
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", tcpAddress, 4000, clientDispatcher)) {
-        try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("client-monitoring2", tcpAddress, 4000, clientDispatcher)) {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
+        try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("client-monitoring2", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
             NetconfMessage response = netconfClient.sendMessage(loadGetMessage());
             assertSessionElementsInResponse(response.getDocument(), 2);
         }
index 96a9effcfc7cdfc4ccf9b28995b26a9eea5ef148..ebfcff3cd4fdc1e957714a5798c7a4977b51e829 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * 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
- */
+* Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,
+* and is available at http://www.eclipse.org/legal/epl-v10.html
+*/
 package org.opendaylight.controller.netconf.it.pax;
 
 import static org.junit.Assert.fail;
@@ -19,14 +19,14 @@ import static org.ops4j.pax.exam.CoreOptions.options;
 import static org.ops4j.pax.exam.CoreOptions.streamBundle;
 import static org.ops4j.pax.exam.CoreOptions.systemPackages;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import io.netty.channel.nio.NioEventLoopGroup;
 
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
-import javax.inject.Inject;
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.junit.Assert;
@@ -35,11 +35,15 @@ import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
 import org.junit.runner.RunWith;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
@@ -52,6 +56,9 @@ import org.xml.sax.SAXException;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
 
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.concurrent.GlobalEventExecutor;
+
 @Ignore
 @RunWith(PaxExam.class)
 public class IdentityRefNetconfTest {
@@ -59,7 +66,11 @@ public class IdentityRefNetconfTest {
     public static final int CLIENT_CONNECTION_TIMEOUT_MILLIS = 15000;
 
     // Wait for controller to start
-    @Inject
+
+    // FIXME move this (pax) test to different module
+    // pax jars contain guava classes that clash with real guava dependencies in non-pax tests
+    //
+    //@Inject
     @Filter(timeout = 60 * 1000)
     BindingAwareBroker broker;
 
@@ -118,15 +129,15 @@ public class IdentityRefNetconfTest {
     public void testIdRef() throws Exception {
         Preconditions.checkNotNull(broker, "Controller not initialized");
 
-        NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
-        NetconfClientDispatcher clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup,
-                CLIENT_CONNECTION_TIMEOUT_MILLIS);
 
         NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
         NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml");
         NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
 
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, CLIENT_CONNECTION_TIMEOUT_MILLIS, clientDispatcher)) {
+        NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
+        Timer timer = new HashedWheelTimer();
+        NetconfClientDispatcherImpl clientDispatcher = new NetconfClientDispatcherImpl(nettyThreadgroup, nettyThreadgroup, timer);
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress))) {
             sendMessage(edit, netconfClient);
             sendMessage(commit, netconfClient);
             sendMessage(getConfig, netconfClient, "id-test",
@@ -138,6 +149,9 @@ public class IdentityRefNetconfTest {
             clientDispatcher.close();
         } catch (Exception e) {
             fail(Throwables.getStackTraceAsString(e));
+        } finally {
+            nettyThreadgroup.shutdownGracefully().get();
+            timer.stop();
         }
     }
 
@@ -157,4 +171,14 @@ public class IdentityRefNetconfTest {
             ParserConfigurationException {
         return XmlFileLoader.xmlFileToNetconfMessage(fileName);
     }
+
+    public NetconfClientConfiguration getClientConfiguration(final InetSocketAddress tcpAddress) {
+        final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
+        b.withAddress(tcpAddress);
+        b.withSessionListener(new SimpleNetconfClientSessionListener());
+        b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
+                CLIENT_CONNECTION_TIMEOUT_MILLIS));
+        b.withConnectionTimeoutMillis(CLIENT_CONNECTION_TIMEOUT_MILLIS);
+        return b.build();
+    }
 }
index c08db906df51a00b5dc39d53bb30be252381b3ca..1f7eed250f5b61725ee32c01aa2b1ce1a3c46f37 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.netconf.mapping.api;
 
+import com.google.common.base.Objects;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 
@@ -51,13 +52,13 @@ public final class HandlingPriority implements Comparable<HandlingPriority> {
 
     @Override
     public int compareTo(HandlingPriority o) {
-        if (this == o){
+        if (this == o) {
             return 0;
         }
-        if (this.equals(CANNOT_HANDLE)){
+        if (isCannotHandle()) {
             return -1;
         }
-        if (o.equals(CANNOT_HANDLE)){
+        if (o.isCannotHandle()) {
             return 1;
         }
 
@@ -70,7 +71,8 @@ public final class HandlingPriority implements Comparable<HandlingPriority> {
         if (priority < o.priority){
             return -1;
         }
-        throw new IllegalStateException("Unexpected state");
+
+        throw new IllegalStateException("Unexpected state comparing " + this + " with " + o);
     }
 
     @Override
@@ -95,4 +97,11 @@ public final class HandlingPriority implements Comparable<HandlingPriority> {
     public int hashCode() {
         return priority != null ? priority.hashCode() : 0;
     }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this)
+                .add("priority", priority)
+                .toString();
+    }
 }
index 51054dd938ac8349447e694ea5c2698a7bc6d5c8..ff950e95e9700289bf9dda3bed79642f1fba096e 100644 (file)
@@ -68,9 +68,9 @@ public final class NetconfSSHServer implements Runnable {
         while (up) {
             logger.trace("Starting new socket thread.");
             try {
-               SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(),authProvider);
+               SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(), authProvider);
             } catch (IOException e) {
-                logger.error("Exception occurred during socket thread initialization {}",e);
+                logger.error("Exception occurred during socket thread initialization {}", e);
             }
         }
     }
index 6ddc8ebb55752dca439e63ee3e70dfa260e79783..2e9a0b9d8bbd256154ff82689e85e556b60c9e90 100644 (file)
@@ -7,42 +7,26 @@
  */
 package org.opendaylight.controller.netconf.ssh.authentication;
 
+import java.io.IOException;
 import org.opendaylight.controller.sal.authorization.AuthResultEnum;
-import org.opendaylight.controller.sal.authorization.UserLevel;
 import org.opendaylight.controller.usermanager.IUserManager;
-import org.opendaylight.controller.usermanager.UserConfig;
-
-import java.util.ArrayList;
-import java.util.List;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 
 public class AuthProvider implements AuthProviderInterface {
 
-    private static IUserManager um; //FIXME static mutable state, no locks
-    private static final String DEFAULT_USER = "netconf";
-    private static final String DEFAULT_PASSWORD = "netconf";
+    private IUserManager um;
     private final String pem;
 
-    public AuthProvider(IUserManager ium, String pemCertificate) throws Exception {
+    public AuthProvider(IUserManager ium, String pemCertificate) throws IllegalArgumentException, IOException {
         checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null");
-        AuthProvider.um = ium;
-        if (AuthProvider.um == null) {
-            throw new Exception("No usermanager service available.");
-        }
-
-        List<String> roles = new ArrayList<String>(1);
-        roles.add(UserLevel.SYSTEMADMIN.toString());
-        AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); //FIXME hardcoded auth
+        checkNotNull(ium, "No user manager service available.");
+        this.um = ium;
         pem = pemCertificate;
     }
 
     @Override
     public boolean authenticated(String username, String password) {
-        if (AuthProvider.um == null) {
-            throw new IllegalStateException("No usermanager service available.");
-        }
-        AuthResultEnum authResult = AuthProvider.um.authenticate(username, password);
+        AuthResultEnum authResult = this.um.authenticate(username, password);
         return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC);
     }
 
@@ -53,11 +37,11 @@ public class AuthProvider implements AuthProviderInterface {
 
     @Override
     public void removeUserManagerService() {
-        AuthProvider.um = null;
+        this.um = null;
     }
 
     @Override
     public void addUserManagerService(IUserManager userManagerService) {
-        AuthProvider.um = userManagerService;
+        this.um = userManagerService;
     }
 }
index 5b8803001ca9a33f71d2cacab990f03891a6891e..ca0c9454d4a5c8934a96da245b41029198e464d6 100644 (file)
@@ -8,12 +8,21 @@
 package org.opendaylight.controller.netconf.ssh.osgi;
 
 import com.google.common.base.Optional;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
 import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
+import org.opendaylight.controller.sal.authorization.UserLevel;
 import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.UserConfig;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -21,16 +30,12 @@ import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
  * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket
- * and listen for client connections. Each client connection creation is handled in separate
+ * and listens for client connections. Each client connection creation is handled in separate
  * {@link org.opendaylight.controller.netconf.ssh.threads.SocketThread} thread.
  * This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}
  * forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream.
@@ -44,6 +49,8 @@ public class NetconfSSHActivator implements BundleActivator{
     private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available.";
     private IUserManager iUserManager;
     private BundleContext context = null;
+    private Optional<String> defaultPassword;
+    private Optional<String> defaultUser;
 
     private ServiceTrackerCustomizer<IUserManager, IUserManager> customizer = new ServiceTrackerCustomizer<IUserManager, IUserManager>(){
         @Override
@@ -79,20 +86,23 @@ public class NetconfSSHActivator implements BundleActivator{
 
     @Override
     public void stop(BundleContext context) throws IOException {
+        if (this.defaultUser.isPresent()){
+            this.iUserManager.removeLocalUser(this.defaultUser.get());
+        }
         if (server != null){
             server.stop();
             logger.trace("Netconf SSH bridge is down ...");
         }
     }
     private void startSSHServer() throws IllegalStateException, IOException {
+        checkNotNull(this.iUserManager, "No user manager service available.");
         logger.trace("Starting netconf SSH  bridge.");
         Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE);
         InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
                 EXCEPTION_MESSAGE, true);
 
         if (sshSocketAddressOptional.isPresent()){
-            String path = NetconfConfigUtil.getPrivateKeyPath(context);
-            path = path.replace("\\", "/");  // FIXME: shouldn't this convert lines to system dependent path separator?
+            String path =  FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(context));
             if (path.equals("")){
                 throw new IllegalStateException("Missing netconf.ssh.pk.path key in configuration file.");
             }
@@ -100,11 +110,10 @@ public class NetconfSSHActivator implements BundleActivator{
             File privateKeyFile = new File(path);
             String privateKeyPEMString = null;
             if (privateKeyFile.exists() == false) {
-                // generate & save to file
                 try {
                     privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
                 } catch (Exception e) {
-                    logger.error("Exception occured while generating PEM string {}",e);
+                    logger.error("Exception occurred while generating PEM string {}",e);
                 }
             } else {
                 // read from file
@@ -117,6 +126,17 @@ public class NetconfSSHActivator implements BundleActivator{
             }
             AuthProvider authProvider = null;
             try {
+                this.defaultPassword = NetconfConfigUtil.getSSHDefaultPassword(context);
+                this.defaultUser = NetconfConfigUtil.getSSHDefaultUser(context);
+                // Since there is no user data store yet (ldap, ...) this adds default user/password to UserManager
+                // if these parameters are set in netconf configuration file.
+                if (defaultUser.isPresent() &&
+                        defaultPassword.isPresent()){
+                    logger.trace(String.format("Default username and password for netconf ssh bridge found. Adding user %s to user manager.",defaultUser.get()));
+                    List<String> roles = new ArrayList<String>(1);
+                    roles.add(UserLevel.SYSTEMADMIN.toString());
+                    iUserManager.addLocalUser(new UserConfig(defaultUser.get(), defaultPassword.get(), roles));
+                }
                 authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
             } catch (Exception e) {
                 logger.error("Error instantiating AuthProvider {}",e);
index d6566c8ffa69f3e0fd46d6775e8ced177cffd911..04639cb36fb665753bda35908321508688e75103 100644 (file)
@@ -66,7 +66,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser
         try {
             conn.setPEMHostKey(authProvider.getPEMAsCharArray(), "netconf");
         } catch (Exception e) {
-            logger.debug("Server authentication setup failed.");
+            logger.warn("Server authentication setup failed.", e);
         }
         conn.setAuthenticationCallback(this);
         conn.setServerConnectionCallback(this);
index aa1afc025d736f154822e88dee11c89766d9bd63..c789206436f1eecb1fd92fc1480a027eb8943d09 100644 (file)
@@ -93,23 +93,19 @@ public abstract class AbstractNetconfSession<S extends NetconfSession, L extends
         return sb.toString();
     }
 
-    protected <T extends ChannelHandler> T removeHandler(final Class<T> handlerType) {
-        return this.channel.pipeline().remove(handlerType);
-    }
-
-    protected void replaceMessageDecoder(final ChannelHandler handler) {
+    protected final void replaceMessageDecoder(final ChannelHandler handler) {
         replaceChannelHandler(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, handler);
     }
 
-    protected void replaceMessageEncoder(final ChannelHandler handler) {
+    protected final void replaceMessageEncoder(final ChannelHandler handler) {
         replaceChannelHandler(AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, handler);
     }
 
-    protected void replaceMessageEncoderAfterNextMessage(final ChannelHandler handler) {
+    protected final void replaceMessageEncoderAfterNextMessage(final ChannelHandler handler) {
         this.delayedEncoder = handler;
     }
 
-    protected void replaceChannelHandler(final String handlerName, final ChannelHandler handler) {
+    protected final void replaceChannelHandler(final String handlerName, final ChannelHandler handler) {
         channel.pipeline().replace(handlerName, handlerName, handler);
     }
 
@@ -124,7 +120,7 @@ public abstract class AbstractNetconfSession<S extends NetconfSession, L extends
         }
         final NetconfEXICodec exiCodec = new NetconfEXICodec(exiParams.getOptions());
         addExiHandlers(exiCodec);
-        logger.debug("EXI handlers added to pipeline on session {}", this);
+        logger.debug("Session {} EXI handlers added to pipeline", this);
     }
 
     protected abstract void addExiHandlers(NetconfEXICodec exiCodec);
index 5521e28818b20fcb9291089ced8867cce787e2e6..b0c8c6dc19e6b3b6c97f90b21fe0e1dc680e0ba3 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
 import org.opendaylight.controller.netconf.util.handler.NetconfChunkAggregator;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
 import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
 import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
@@ -74,7 +75,7 @@ extends AbstractSessionNegotiator<NetconfHelloMessage, S> {
     }
 
     @Override
-    protected void startNegotiation() {
+    protected final void startNegotiation() {
         final Optional<SslHandler> sslHandler = getSslHandler(channel);
         if (sslHandler.isPresent()) {
             Future<Channel> future = sslHandler.get().handshakeFuture();
@@ -125,27 +126,22 @@ extends AbstractSessionNegotiator<NetconfHelloMessage, S> {
 
         // FIXME, make sessionPreferences return HelloMessage, move NetconfHelloMessage to API
         sendMessage((NetconfHelloMessage)helloMessage);
+
+        replaceHelloMessageOutboundHandler();
         changeState(State.OPEN_WAIT);
     }
+
     private void cancelTimeout() {
         if(timeout!=null) {
             timeout.cancel();
         }
     }
 
-    @Override
-    protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
-        S session = getSessionForHelloMessage(netconfMessage)   ;
-        negotiationSuccessful(session);
-    }
-
     protected final S getSessionForHelloMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
         Preconditions.checkNotNull(netconfMessage, "netconfMessage");
 
         final Document doc = netconfMessage.getDocument();
 
-        replaceHelloMessageHandlers();
-
         if (shouldUseChunkFraming(doc)) {
             insertChunkFramingToPipeline();
         }
@@ -157,23 +153,44 @@ extends AbstractSessionNegotiator<NetconfHelloMessage, S> {
     /**
      * Insert chunk framing handlers into the pipeline
      */
-    protected void insertChunkFramingToPipeline() {
+    private void insertChunkFramingToPipeline() {
         replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_FRAME_ENCODER,
                 FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK));
         replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
                 new NetconfChunkAggregator());
     }
 
-    protected boolean shouldUseChunkFraming(Document doc) {
+    private boolean shouldUseChunkFraming(Document doc) {
         return containsBase11Capability(doc)
                 && containsBase11Capability(sessionPreferences.getHelloMessage().getDocument());
     }
 
     /**
-     * Remove special handlers for hello message. Insert regular netconf xml message (en|de)coders.
+     * Remove special inbound handler for hello message. Insert regular netconf xml message (en|de)coders.
+     *
+     * Inbound hello message handler should be kept until negotiation is successful
+     * It caches any non-hello messages while negotiation is still in progress
+     */
+    protected final void replaceHelloMessageInboundHandler(final S session) {
+        ChannelHandler helloMessageHandler = replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
+
+        Preconditions.checkState(helloMessageHandler instanceof NetconfXMLToHelloMessageDecoder,
+                "Pipeline handlers misplaced on session: %s, pipeline: %s", session, channel.pipeline());
+        Iterable<NetconfMessage> netconfMessagesFromNegotiation =
+                ((NetconfXMLToHelloMessageDecoder) helloMessageHandler).getPostHelloNetconfMessages();
+
+        // Process messages received during negotiation
+        // The hello message handler does not have to be synchronized, since it is always call from the same thread by netty
+        // It means, we are now using the thread now
+        for (NetconfMessage message : netconfMessagesFromNegotiation) {
+            session.handleMessage(message);
+        }
+    }
+
+    /**
+     * Remove special outbound handler for hello message. Insert regular netconf xml message (en|de)coders.
      */
-    protected void replaceHelloMessageHandlers() {
-        replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
+    private void replaceHelloMessageOutboundHandler() {
         replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, new NetconfMessageToXMLEncoder());
     }
 
@@ -183,7 +200,7 @@ extends AbstractSessionNegotiator<NetconfHelloMessage, S> {
 
     protected abstract S getSession(L sessionListener, Channel channel, NetconfHelloMessage message) throws NetconfDocumentedException;
 
-    protected synchronized void changeState(final State newState) {
+    private synchronized void changeState(final State newState) {
         logger.debug("Changing state from : {} to : {}", state, newState);
         Preconditions.checkState(isStateChangePermitted(state, newState), "Cannot change state from %s to %s", state,
                 newState);
index cbfbfe1c05a21ebb5db74b5973ce32fc90f86c98..ae330d67e68344e16d1904b7c1547caea73cadb8 100644 (file)
@@ -34,8 +34,6 @@ public final class NetconfEXIToMessageDecoder extends ByteToMessageDecoder {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfEXIToMessageDecoder.class);
 
-//    private static final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
-
     private final NetconfEXICodec codec;
 
     public NetconfEXIToMessageDecoder(final NetconfEXICodec codec) {
@@ -50,9 +48,9 @@ public final class NetconfEXIToMessageDecoder extends ByteToMessageDecoder {
          * the use of EXI, which means the next message needs to be decoded not by us, but rather
          * by the XML decoder.
          */
-        // If empty Byte buffer is passed to r.parse, EOFException is thrown
 
-        if (in.readableBytes() == 0) {
+        // If empty Byte buffer is passed to r.parse, EOFException is thrown
+        if (in.isReadable() == false) {
             LOG.debug("No more content in incoming buffer.");
             return;
         }
@@ -69,7 +67,6 @@ public final class NetconfEXIToMessageDecoder extends ByteToMessageDecoder {
         final DOMResult domResult = new DOMResult();
         handler.setResult(domResult);
 
-
         try (final InputStream is = new ByteBufInputStream(in)) {
             r.parse(new InputSource(is));
         }
index b930b65b9742625071f6f0618be9461add72a2c7..361d4fcee908018eac90a54844569ced70c22a21 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.netconf.util.handler;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufUtil;
 import io.netty.channel.ChannelHandlerContext;
@@ -36,7 +38,12 @@ import org.xml.sax.SAXException;
  * Customized NetconfXMLToMessageDecoder that reads additional header with
  * session metadata from
  * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage}
- * . Used by netconf server to retrieve information about session metadata.
+ *
+ *
+ * This handler should be replaced in pipeline by regular message handler as last step of negotiation.
+ * It serves as a message barrier and halts all non-hello netconf messages.
+ * Netconf messages after hello should be processed once the negotiation succeeded.
+ *
  */
 public final class NetconfXMLToHelloMessageDecoder extends ByteToMessageDecoder {
     private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToHelloMessageDecoder.class);
@@ -49,6 +56,12 @@ public final class NetconfXMLToHelloMessageDecoder extends ByteToMessageDecoder
             new byte[] { '\r', '\n', '[' },
             new byte[] { '\n', '[' });
 
+    // State variables do not have to by synchronized
+    // Netty uses always the same (1) thread per pipeline
+    // We use instance of this per pipeline
+    private List<NetconfMessage> nonHelloMessages = Lists.newArrayList();
+    private boolean helloReceived = false;
+
     @Override
     @VisibleForTesting
     public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws IOException, SAXException, NetconfDocumentedException {
@@ -79,18 +92,39 @@ public final class NetconfXMLToHelloMessageDecoder extends ByteToMessageDecoder
 
             Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
 
-            final NetconfMessage message;
-            if (additionalHeader != null) {
-                message = new NetconfHelloMessage(doc, NetconfHelloMessageAdditionalHeader.fromString(additionalHeader));
+            final NetconfMessage message = getNetconfMessage(additionalHeader, doc);
+            if (message instanceof NetconfHelloMessage) {
+                Preconditions.checkState(helloReceived == false,
+                        "Multiple hello messages received, unexpected hello: %s",
+                        XmlUtil.toString(message.getDocument()));
+                out.add(message);
+                helloReceived = true;
+            // Non hello message, suspend the message and insert into cache
             } else {
-                message = new NetconfHelloMessage(doc);
+                Preconditions.checkState(helloReceived, "Hello message not received, instead received: %s",
+                        XmlUtil.toString(message.getDocument()));
+                LOG.debug("Netconf message received during negotiation, caching {}",
+                        XmlUtil.toString(message.getDocument()));
+                nonHelloMessages.add(message);
             }
-            out.add(message);
         } finally {
             in.discardReadBytes();
         }
     }
 
+    private NetconfMessage getNetconfMessage(final String additionalHeader, final Document doc) throws NetconfDocumentedException {
+        NetconfMessage msg = new NetconfMessage(doc);
+        if(NetconfHelloMessage.isHelloMessage(msg)) {
+            if (additionalHeader != null) {
+                return new NetconfHelloMessage(doc, NetconfHelloMessageAdditionalHeader.fromString(additionalHeader));
+            } else {
+                return new NetconfHelloMessage(doc);
+            }
+        }
+
+        return msg;
+    }
+
     private int getAdditionalHeaderEndIndex(byte[] bytes) {
         for (byte[] possibleEnd : POSSIBLE_ENDS) {
             int idx = findByteSequence(bytes, possibleEnd);
@@ -155,4 +189,10 @@ public final class NetconfXMLToHelloMessageDecoder extends ByteToMessageDecoder
         return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
     }
 
+    /**
+     * @return Collection of NetconfMessages that were not hello, but were received during negotiation
+     */
+    public Iterable<NetconfMessage> getPostHelloNetconfMessages() {
+        return nonHelloMessages;
+    }
 }
index 89f76f39e5eafed6526388e9305a129d97bf7517..23f48b31d822ff2b4c10351c844718989ca3b7c2 100644 (file)
@@ -7,13 +7,6 @@
  */
 package org.opendaylight.controller.netconf.util.handler;
 
-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.io.IOException;
 import java.util.List;
 
 import org.opendaylight.controller.netconf.api.NetconfMessage;
@@ -22,14 +15,20 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
-import org.xml.sax.SAXException;
+
+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;
 
 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 IOException, SAXException {
+    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+
         if (in.readableBytes() != 0) {
             LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
             out.add(new NetconfMessage(XmlUtil.readXmlToDocument(new ByteBufInputStream(in))));
index 3fd25e814d697d37e607e1e0ade520db254e83a8..86b2ba1671478a022e30f7dd8c724b07c1d4d703 100644 (file)
@@ -8,17 +8,21 @@
 
 package org.opendaylight.controller.netconf.util.messages;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+
+import java.util.Set;
+
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-import java.util.Set;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
 
 /**
  * NetconfMessage that can carry additional header with session metadata. See {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader}
@@ -43,10 +47,10 @@ public final class NetconfHelloMessage extends NetconfMessage {
         return additionalHeader== null ? Optional.<NetconfHelloMessageAdditionalHeader>absent() : Optional.of(additionalHeader);
     }
 
-    private static void checkHelloMessage(Document doc) throws NetconfDocumentedException {
-        XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), HELLO_TAG,
-                XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
-
+    private static void checkHelloMessage(Document doc) {
+        Preconditions.checkArgument(isHelloMessage(doc),
+                "Hello message invalid format, should contain %s tag from namespace %s, but is: %s", HELLO_TAG,
+                XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlUtil.toString(doc));
     }
 
     public static NetconfHelloMessage createClientHello(Iterable<String> capabilities,
@@ -81,4 +85,21 @@ public final class NetconfHelloMessage extends NetconfMessage {
         doc.getDocumentElement().appendChild(sessionIdElement);
         return new NetconfHelloMessage(doc);
     }
+
+    public static boolean isHelloMessage(final NetconfMessage msg) {
+        Document document = msg.getDocument();
+        return isHelloMessage(document);
+    }
+
+    private static boolean isHelloMessage(final Document document) {
+        XmlElement element = XmlElement.fromDomElement(document.getDocumentElement());
+        try {
+            return element.getName().equals(HELLO_TAG) &&
+                   element.hasNamespace() &&
+                   element.getNamespace().equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+        } catch (MissingNameSpaceException e) {
+            // Cannot happen, since we check for hasNamespace
+            throw new IllegalStateException(e);
+        }
+    }
 }
index 5b9707f2b52fff9875cd18e63d91ca257b815a0c..fdcaa2a5b8c98616385231d5c6c8c0f7e39c0adc 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.controller.netconf.util.messages;
 
 import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
@@ -38,13 +40,15 @@ public final class SendErrorExceptionUtil {
             final NetconfDocumentedException sendErrorException) {
         logger.trace("Sending error {}", sendErrorException.getMessage(), sendErrorException);
         final Document errorDocument = createDocument(sendErrorException);
-        session.sendMessage(new NetconfMessage(errorDocument));
+        ChannelFuture f = session.sendMessage(new NetconfMessage(errorDocument));
+        f.addListener(new SendErrorVerifyingListener(sendErrorException));
     }
 
     public static void sendErrorMessage(Channel channel, NetconfDocumentedException sendErrorException) {
         logger.trace("Sending error {}", sendErrorException.getMessage(), sendErrorException);
         final Document errorDocument = createDocument(sendErrorException);
-        channel.writeAndFlush(new NetconfMessage(errorDocument));
+        ChannelFuture f = channel.writeAndFlush(new NetconfMessage(errorDocument));
+        f.addListener(new SendErrorVerifyingListener(sendErrorException));
     }
 
     public static void sendErrorMessage(NetconfSession session, NetconfDocumentedException sendErrorException,
@@ -52,7 +56,8 @@ public final class SendErrorExceptionUtil {
         final Document errorDocument = createDocument(sendErrorException);
         logger.trace("Sending error {}", XmlUtil.toString(errorDocument));
         tryToCopyAttributes(incommingMessage.getDocument(), errorDocument, sendErrorException);
-        session.sendMessage(new NetconfMessage(errorDocument));
+        ChannelFuture f = session.sendMessage(new NetconfMessage(errorDocument));
+        f.addListener(new SendErrorVerifyingListener(sendErrorException));
     }
 
     private static void tryToCopyAttributes(final Document incommingDocument, final Document errorDocument,
@@ -133,4 +138,20 @@ public final class SendErrorExceptionUtil {
         return errorDocument;
     }
 
+    /**
+     * Checks if netconf error was sent successfully.
+     */
+    private static final class SendErrorVerifyingListener implements ChannelFutureListener {
+        private final NetconfDocumentedException sendErrorException;
+
+        public SendErrorVerifyingListener(final NetconfDocumentedException sendErrorException) {
+            this.sendErrorException = sendErrorException;
+        }
+
+        @Override
+        public void operationComplete(final ChannelFuture channelFuture) throws Exception {
+            Preconditions.checkState(channelFuture.isSuccess(), "Unable to send exception {}", sendErrorException,
+                    channelFuture.cause());
+        }
+    }
 }
index b23a2d6697b2ab5623431741fb0ecb374cb22411..f89df2ac7cc331908f64ed8d05b2dc826f4d7757 100644 (file)
@@ -9,12 +9,11 @@
 package org.opendaylight.controller.netconf.util.osgi;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import java.net.InetSocketAddress;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import java.net.InetSocketAddress;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 
 public final class NetconfConfigUtil {
@@ -32,6 +31,8 @@ public final class NetconfConfigUtil {
     private static final String ADDRESS_SUFFIX_PROP = ".address";
     private static final String CLIENT_PROP = ".client";
     private static final String PRIVATE_KEY_PATH_PROP = ".pk.path";
+    private static final String SSH_DEFAULT_USER = ".default.user";
+    private static final String SSH_DEFAULT_PASSWORD = ".default.password";
 
     private static final String CONNECTION_TIMEOUT_MILLIS_PROP = "connectionTimeoutMillis";
     private static final long DEFAULT_TIMEOUT_MILLIS = 5000;
@@ -72,6 +73,13 @@ public final class NetconfConfigUtil {
     public static String getPrivateKeyPath(BundleContext context){
         return getPropertyValue(context,PREFIX_PROP + InfixProp.ssh +PRIVATE_KEY_PATH_PROP);
     }
+    public static Optional<String> getSSHDefaultUser(BundleContext context){
+        return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_USER);
+    }
+    public static Optional<String> getSSHDefaultPassword(BundleContext context){
+        return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_PASSWORD);
+    }
+
     private static String getPropertyValue(BundleContext context, String propertyName){
         String propertyValue = context.getProperty(propertyName);
         if (propertyValue == null){
@@ -79,6 +87,13 @@ public final class NetconfConfigUtil {
         }
         return propertyValue;
     }
+    private static Optional<String> getOptionalPropertyValue(BundleContext context, String propertyName){
+        String propertyValue = context.getProperty(propertyName);
+        if (Strings.isNullOrEmpty(propertyValue)){
+            return Optional.absent();
+        }
+        return Optional.fromNullable(propertyValue);
+    }
     /**
      * @param context
      *            from which properties are being read.
index ae48a3a45118533785f5c3175a68df107d9c7c0a..86e6a360dd50c67d38fc70cf4147bc328f3d4274 100644 (file)
@@ -164,7 +164,7 @@ public class Pool {
     public boolean removeVIP(String name){
         for(VIP vip: this.vips){
             if(vip.getName().equals(name)){
-                this.members.remove(vip);
+                this.vips.remove(vip);
                 return true;
             }
         }
index 07252b06f78dfb2a80a4c88d112f6b3f41fd5422..e95ab8095d08c8b3fcf80094fc958d0053b4d256 100644 (file)
@@ -115,6 +115,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
      * only subnet returned. As soon as a user-configured subnet is created this one will
      * vanish.
      */
+    private static final String DISABLE_DEFAULT_SUBNET_PROP = "switchmanager.disableDefaultSubnetGateway";
+    private static final String DISABLE_DEFAULT_SUBNET_PROP_VAL = System.getProperty(DISABLE_DEFAULT_SUBNET_PROP);
+    private static final boolean USE_DEFAULT_SUBNET_GW = !Boolean.valueOf(DISABLE_DEFAULT_SUBNET_PROP_VAL);
     protected static final SubnetConfig DEFAULT_SUBNETCONFIG;
     protected static final Subnet DEFAULT_SUBNET;
     protected static final String DEFAULT_SUBNET_NAME = "default (cannot be modifed)";
@@ -288,9 +291,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
     @Override
     public List<SubnetConfig> getSubnetsConfigList() {
         // if there are no subnets, return the default subnet
-        if(subnetsConfigList.size() == 0){
+        if (USE_DEFAULT_SUBNET_GW && subnetsConfigList.isEmpty()) {
             return Collections.singletonList(DEFAULT_SUBNETCONFIG);
-        }else{
+        } else {
             return new ArrayList<SubnetConfig>(subnetsConfigList.values());
         }
     }
@@ -298,9 +301,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
     @Override
     public SubnetConfig getSubnetConfig(String subnet) {
         // if there are no subnets, return the default subnet
-        if(subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)){
+        if (USE_DEFAULT_SUBNET_GW && subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
             return DEFAULT_SUBNETCONFIG;
-        }else{
+        } else {
             return subnetsConfigList.get(subnet);
         }
     }
diff --git a/pom.xml b/pom.xml
index 792c66dbda37292887bb54a03208df9e786e1404..64ed6c7d80794a0e0030e67411d60ab0245d5ae3 100644 (file)
--- a/pom.xml
+++ b/pom.xml
     <module>opendaylight/commons/opendaylight</module>
     <module>opendaylight/commons/parent</module>
     <module>opendaylight/commons/logback_settings</module>
+
+    <!-- Karaf Distribution 
+    <module>feature</module>
+    <module>opendaylight/dummy-console</module> -->
+    <module>opendaylight/distribution/opendaylight-karaf</module>
   </modules>
   <scm>
     <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>