Merge "Bug 2731: Discard changes only when transaction exist."
authorTony Tkacik <ttkacik@cisco.com>
Tue, 24 Feb 2015 09:39:34 +0000 (09:39 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 24 Feb 2015 09:39:34 +0000 (09:39 +0000)
239 files changed:
features/akka/pom.xml
features/config-netty/pom.xml
features/config-persister/pom.xml
features/config/pom.xml
features/extras/pom.xml
features/flow/pom.xml
features/mdsal/pom.xml
features/mdsal/src/main/resources/features.xml
features/netconf-connector/pom.xml
features/netconf-connector/src/main/resources/features.xml
features/netconf/pom.xml
features/netconf/src/main/resources/features.xml
features/protocol-framework/pom.xml
features/restconf/pom.xml
opendaylight/archetypes/opendaylight-startup/src/main/resources/META-INF/maven/archetype-metadata.xml
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/api/.gitignore [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-api/.gitignore with 100% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/api/pom.xml [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-api/pom.xml with 100% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/api/src/main/yang/__artifactId__.yang [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-api/src/main/yang/__artifactId__.yang with 100% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/artifacts/pom.xml [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-artifacts/pom.xml with 100% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/features/pom.xml [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-features/pom.xml with 97% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/features/src/main/features/features.xml [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-features/src/main/features/features.xml with 78% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/pom.xml [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-impl/pom.xml with 80% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/main/config/default-config.xml [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-impl/src/main/config/default-config.xml with 96% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/main/java/__packageInPathFormat__/impl/__classPrefix__Provider.java [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-impl/src/main/java/__packageInPathFormat__/__classPrefix__Provider.java with 97% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__Module.java [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ImplModule.java with 55% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ModuleFactory.java [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ImplModuleFactory.java with 80% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/main/yang/__artifactId__-impl.yang [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-impl/src/main/yang/__artifactId__-impl.yang with 87% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/__packageInPathFormat__/impl/__classPrefix__ProviderTest.java [new file with mode: 0644]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ModuleFactoryTest.java [new file with mode: 0644]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ModuleTest.java [new file with mode: 0644]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/karaf/pom.xml [moved from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-karaf/pom.xml with 77% similarity]
opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/pom.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConfigRegistry.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/LookupRegistry.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionLookupRegistry.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/BeanReader.java [new file with mode: 0644]
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryClient.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionClient.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/TestingConfigTransactionController.java
opendaylight/config/yang-jmx-generator-plugin/pom.xml
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGenerator.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java
opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java
opendaylight/md-sal/messagebus-impl/pom.xml
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/Topic.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/FollowerLogInformationImpl.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/ApplyState.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractLeader.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/messages/InstallSnapshot.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/MockRaftActorContext.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractLeaderTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/IsolatedLeaderTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/ForwardMessageToBehaviorActor.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MessageCollectorActor.java
opendaylight/md-sal/sal-akka-raft/src/test/resources/simplelogger.properties
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataObjectModification.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeService.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeIdentifier.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeModification.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/md/sal/binding/data/ConcurrentImplicitCreateTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/md/sal/binding/data/WildcardedDataChangeListenerTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DeleteNestedAugmentationListenParentTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/FlagsSerializationTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentListenAugmentTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentReadChildTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/ChangeOriginatedInDomBrokerTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerMountPointTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/DOMRpcServiceTestBugfix560.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java
opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/akka.conf
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizer.java
opendaylight/md-sal/sal-common-impl/src/test/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizerTest.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ConcurrentDOMDataBroker.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionContextImpl.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/Dispatchers.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/MessageTracker.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DatastoreContextTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/DispatchersTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MessageTrackerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application-with-custom-dispatchers.conf [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/pom.xml
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeIdentifier.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeInaccessibleException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeListeningException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeLoopException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducer.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerBusyException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShard.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShardingConflictException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShardingService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/test/java/org/opendaylight/controller/md/sal/dom/api/AbstractDOMDataTreeServiceTestSuite.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/CommitCoordinationTask.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/SerializedDOMDataBroker.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardRegistration.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataTree.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataTreeProducer.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardingTableEntry.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerPerformanceTest.java
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java
opendaylight/md-sal/sal-dom-xsql/pom.xml
opendaylight/md-sal/sal-dummy-distributed-datastore/pom.xml
opendaylight/md-sal/sal-dummy-distributed-datastore/src/main/java/org/opendaylight/controller/dummy/datastore/DummyShard.java
opendaylight/md-sal/sal-dummy-distributed-datastore/src/main/resources/simplelogger.properties
opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java
opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaUpdateForTransactionTest.java
opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/TestDCLExecutorService.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NotificationHandler.java
opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-of-migration-test-model.yang [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/InstanceConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Datastore.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/get/Get.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/GetConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/getconfig/RunningDatastoreQueryStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceImpl.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/YangStoreService.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherImpl.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java
opendaylight/netconf/ietf-netconf-monitoring/src/main/yang/ietf-netconf-monitoring.yang
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/CurrentSchemaContext.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/Get.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/GetConfig.java
opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang
opendaylight/netconf/mdsal-netconf-monitoring/pom.xml [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/MonitoringToMdsalWriter.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/NetconfMdsalMonitoringMapperModule.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/NetconfMdsalMonitoringMapperModuleFactory.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/NetconfMonitoringOperationService.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/NetconfMonitoringOperationServiceFactory.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-monitoring/src/main/yang/netconf-mdsal-monitoring.yang [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/Capability.java [moved from opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/Capability.java with 93% similarity]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/CapabilityListener.java [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/NetconfMonitoringService.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/SessionListener.java [moved from opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/SessionMonitoringService.java with 59% similarity]
opendaylight/netconf/netconf-api/src/main/yang/netconf-northbound.yang
opendaylight/netconf/netconf-artifacts/pom.xml
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfMapperAggregatorModule.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfMapperAggregatorModuleFactory.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerDispatcherModule.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerMonitoringModule.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerMonitoringModuleFactory.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/CapabilityProviderImpl.java [deleted file]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListenerFactory.java [deleted file]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/CapabilityProvider.java [deleted file]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommit.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/AggregatedNetconfOperationServiceFactory.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfMonitoringServiceImpl.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryListenerImpl.java [deleted file]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTracker.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshotImpl.java [deleted file]
opendaylight/netconf/netconf-impl/src/main/yang/netconf-northbound-impl.yang
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfDispatcherImplTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfMonitoringServiceImplTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommitTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivatorTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTrackerTest.java
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/NetconfConfigPersisterITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITMonitoringTest.java
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationProvider.java [deleted file]
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationService.java
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceFactory.java
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceFactoryListener.java [moved from opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryListener.java with 79% similarity]
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceSnapshot.java [deleted file]
opendaylight/netconf/netconf-mapping-api/src/main/yang/netconf-northbound-mapper.yang
opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/GetSchema.java [moved from opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java with 75% similarity]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationService.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTracker.java
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/GetSchemaTest.java [moved from opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchemaTest.java with 82% similarity]
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationServiceTest.java
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java
opendaylight/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/controller/netconf/notifications/impl/osgi/Activator.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/FakeModuleBuilderCapability.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/ModuleBuilderCapability.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java
opendaylight/netconf/pom.xml

index f804505c64d2c57ef8d95fc0091a2b0b74285ed6..418597218085fb9fcaf1f078f5456c2ff12f0ec2 100644 (file)
     -->
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
-      <version>${feature.test.version}</version>
       <scope>test</scope>
     </dependency>
     <!-- dependency for opendaylight-karaf-empty for use by testing -->
                 <karaf.distro.version>${karaf.empty.version}</karaf.distro.version>
               </systemPropertyVariables>
               <dependenciesToScan>
-               <dependency>org.opendaylight.yangtools:features-test</dependency>
+               <dependency>org.opendaylight.odlparent:features-test</dependency>
               </dependenciesToScan>
             </configuration>
           </plugin>
index 0057fc05c71fe915868058d2eaca20936075a604..71b28415b5148791483c73b5a131838caa6d2754 100644 (file)
@@ -56,7 +56,7 @@
     </dependency>
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
     </dependency>
   </dependencies>
             <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
           </systemPropertyVariables>
           <dependenciesToScan>
-           <dependency>org.opendaylight.yangtools:features-test</dependency>
+           <dependency>org.opendaylight.odlparent:features-test</dependency>
           </dependenciesToScan>
         </configuration>
       </plugin>
index f3b42ca143785607fa635c2856d0810286ba7177..6fae0e76417d896dbc09bbf4a193170676befd8b 100644 (file)
@@ -81,7 +81,7 @@
     </dependency>
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
     </dependency>
   </dependencies>
             <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
           </systemPropertyVariables>
           <dependenciesToScan>
-           <dependency>org.opendaylight.yangtools:features-test</dependency>
+           <dependency>org.opendaylight.odlparent:features-test</dependency>
           </dependenciesToScan>
         </configuration>
       </plugin>
index 1fa248615c06a0974d5d741eaca91c03c579e06f..683ce3dab1c38aac465f93b0870348c3a892a743 100644 (file)
@@ -88,7 +88,7 @@
     </dependency>
     <!-- test the features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
     </dependency>
   </dependencies>
             <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
           </systemPropertyVariables>
           <dependenciesToScan>
-           <dependency>org.opendaylight.yangtools:features-test</dependency>
+           <dependency>org.opendaylight.odlparent:features-test</dependency>
           </dependenciesToScan>
         </configuration>
       </plugin>
index 20089c726a3c9df7a1f1690bbacfe4c295d35dd1..6ac5872f0086b05bcdd965ed5d90c81cc4858afd 100644 (file)
@@ -23,7 +23,6 @@
         <branding.version>1.1.0-SNAPSHOT</branding.version>
         <karaf.resources.version>1.5.0-SNAPSHOT</karaf.resources.version>
         <karaf.version>3.0.1</karaf.version>
-        <feature.test.version>0.7.0-SNAPSHOT</feature.test.version>
         <karaf.empty.version>1.5.0-SNAPSHOT</karaf.empty.version>
         <surefire.version>2.16</surefire.version>
     </properties>
@@ -34,9 +33,8 @@
             <version>${jolokia.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
+            <groupId>org.opendaylight.odlparent</groupId>
             <artifactId>features-test</artifactId>
-            <version>${feature.test.version}</version>
             <scope>test</scope>
         </dependency>
         <!-- dependency for opendaylight-karaf-empty for use by testing -->
                         <karaf.distro.version>${karaf.empty.version}</karaf.distro.version>
                     </systemPropertyVariables>
                     <dependenciesToScan>
-                        <dependency>org.opendaylight.yangtools:features-test</dependency>
+                        <dependency>org.opendaylight.odlparent:features-test</dependency>
                     </dependenciesToScan>
                 </configuration>
             </plugin>
index 53b45d28103e5ea02df441083748616341147e2e..ad513e5d564db03f3a8226de6a139713590b20d8 100644 (file)
@@ -74,7 +74,7 @@
     </dependency>
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
     </dependency>
   </dependencies>
             <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
           </systemPropertyVariables>
           <dependenciesToScan>
-           <dependency>org.opendaylight.yangtools:features-test</dependency>
+           <dependency>org.opendaylight.odlparent:features-test</dependency>
           </dependenciesToScan>
         </configuration>
       </plugin>
index c63b39c74d50df358e2393624a4de99eb97bf839..35edb286ab49a003389b9e2cf93b10d3123af674 100644 (file)
       <artifactId>sal-inmemory-datastore</artifactId>
     </dependency>
 
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>mdsal-netconf-connector</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>mdsal-netconf-monitoring</artifactId>
+      </dependency>
+
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-netconf-connector</artifactId>
 
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
 
             <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
           </systemPropertyVariables>
           <dependenciesToScan>
-           <dependency>org.opendaylight.yangtools:features-test</dependency>
+           <dependency>org.opendaylight.odlparent:features-test</dependency>
           </dependenciesToScan>
         </configuration>
       </plugin>
index 5b9f4a674a733a7850a40b83622b34b43b1e9fff..4b9f8c2288cb8db0e509e5b13774867ed1c62af8 100644 (file)
     </feature>
 
     <!-- TODO move to netconf features, however there are some weird dependencies on features-config-persister all over that cause cyclic dependencies-->
-    <feature name='odl-netconf-mdsal' version='${project.version}' description="OpenDaylight :: Netconf :: All">
+    <!-- TODO when installing this in pure karaf distro, many optimistic lock exceptions are thrown from config manager -->
+    <feature name='odl-netconf-mdsal' version='${project.version}' description="OpenDaylight :: Netconf :: Mdsal">
         <feature version='${config.version}'>odl-config-all</feature>
         <feature version='${netconf.version}'>odl-netconf-all</feature>
         <bundle>mvn:org.opendaylight.controller/netconf-ssh/${netconf.version}</bundle>
         <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
         <bundle>mvn:org.opendaylight.controller/mdsal-netconf-connector/${netconf.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller/mdsal-netconf-monitoring/${netconf.version}</bundle>
         <!-- TODO 01-netconf.xml file requires netconf-config-dispatcher to be present and its part of netconf-connector features. Clean Up-->
         <bundle>mvn:org.opendaylight.controller/netconf-config-dispatcher/${config.version}</bundle>
         <configfile finalname='${config.configfile.directory}/${config.netconf.client.configfile}'>mvn:org.opendaylight.controller/netconf-config/${netconf.version}/xml/config</configfile>
index 4e94996634716590376611354356a7085e4e3d38..9cb2b1e33ffceaa6c20b92b0e67a5b601a30fe43 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-config-dispatcher</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>mdsal-netconf-connector</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-tcp</artifactId>
     <!-- test to validate features.xml -->
    <!--FIXME BUG-2195 When running single feature tests for netconf connector, features including ssh proxy server always fail (this behavior does not appear when running karaf distro directly)-->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
-      <version>${yangtools.version}</version>
       <scope>test</scope>
     </dependency>
     <!-- dependency for opendaylight-karaf-empty for use by testing -->
                 <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
               </systemPropertyVariables>
               <dependenciesToScan>
-               <dependency>org.opendaylight.yangtools:features-test</dependency>
+               <dependency>org.opendaylight.odlparent:features-test</dependency>
               </dependenciesToScan>
             </configuration>
           </plugin>
index 92e6507d2178a5a17997be74d6bb59b4d9006ee9..7cabbb492910502c8e0ebe2818414a65604e959e 100644 (file)
     </feature>
     <feature name='odl-netconf-ssh' version='${netconf.version}' description="OpenDaylight :: Netconf Connector :: SSH">
         <feature version='${netconf.version}'>odl-netconf-tcp</feature>
+        <feature version='${config.version}'>odl-config-netty</feature>
         <!-- FIXME: This introduces cycle between projects, which makes version updates
                     harder. Should be moved to different.
         -->
index 4edd93629408d1e1fec37e96b879976ec0f23677..b28a53b65c72a0dbf0860a0febbed3fc88c4c69f 100644 (file)
     </dependency>
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
-      <version>${yangtools.version}</version>
       <scope>test</scope>
     </dependency>
     <!-- dependency for opendaylight-karaf-empty for use by testing -->
             <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
           </systemPropertyVariables>
           <dependenciesToScan>
-            <dependency>org.opendaylight.yangtools:features-test</dependency>
+            <dependency>org.opendaylight.odlparent:features-test</dependency>
           </dependenciesToScan>
         </configuration>
       </plugin>
index a65502124bc92aab4fddd4bfae6d5327eab49c40..aa8287d70928690cd9c3f4c30247b4597f167fe4 100644 (file)
@@ -27,6 +27,7 @@
     <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring-extension/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf-inet-types.version}</bundle>
     <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types/${ietf-yang-types.version}</bundle>
+    <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types-20130715/2013.07.15.7-SNAPSHOT</bundle>
   </feature>
   <feature name='odl-netconf-mapping-api' version='${project.version}' description="OpenDaylight :: Netconf :: Mapping API">
     <feature version='${project.version}'>odl-netconf-api</feature>
index d5387b43c3ee7c0bfd56de52e466297828074eb1..f663c1ce3e94b564907fec3ddf4847c8942722f5 100644 (file)
@@ -28,7 +28,7 @@
     </dependency>
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
     </dependency>
   </dependencies>
@@ -86,7 +86,7 @@
             <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
           </systemPropertyVariables>
           <dependenciesToScan>
-           <dependency>org.opendaylight.yangtools:features-test</dependency>
+           <dependency>org.opendaylight.odlparent:features-test</dependency>
           </dependenciesToScan>
         </configuration>
       </plugin>
index 632b4cd592277304b70e832a093853881e360ecd..347a19a75af50cf293728f80f68ee8c0465a0dde 100644 (file)
     -->
     <!-- test to validate features.xml -->
     <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
+      <groupId>org.opendaylight.odlparent</groupId>
       <artifactId>features-test</artifactId>
-      <version>${yangtools.version}</version>
       <scope>test</scope>
     </dependency>
     <!-- dependency for opendaylight-karaf-empty for use by testing -->
                 <karaf.distro.version>${commons.opendaylight.version}</karaf.distro.version>
               </systemPropertyVariables>
               <dependenciesToScan>
-               <dependency>org.opendaylight.yangtools:features-test</dependency>
+               <dependency>org.opendaylight.odlparent:features-test</dependency>
               </dependenciesToScan>
             </configuration>
           </plugin>
index 7057a86fe59d32a459834c0d3703c61ed272df83..6eab884cc52062f9150e50184729a74022acaff3 100644 (file)
@@ -28,7 +28,7 @@
 
     <!-- karaf distro -->
     <fileSet filtered="true" encoding="UTF-8">
-        <directory>__artifactId__-karaf</directory>
+        <directory>karaf</directory>
         <includes>
             <include>pom.xml</include>
         </includes>
     <!-- features -->
 
     <fileSet filtered="true" encoding="UTF-8">
-        <directory>__artifactId__-features</directory>
+        <directory>features</directory>
         <includes>
             <include>pom.xml</include>
         </includes>
     </fileSet>
     <fileSet filtered="true" encoding="UTF-8">
-        <directory>__artifactId__-features/src/main/features</directory>
+        <directory>features/src/main/features</directory>
         <includes>
             <include>**/*.xml</include>
           </includes>
     <!-- impl -->
 
     <fileSet filtered="true" encoding="UTF-8">
-        <directory>__artifactId__-impl</directory>
+        <directory>impl</directory>
         <includes>
             <include>pom.xml</include>
         </includes>
     </fileSet>
     <fileSet filtered="true" encoding="UTF-8">
-        <directory>__artifactId__-impl/src/main/java</directory>
+        <directory>impl/src/main/java</directory>
         <includes>
             <include>**/*.java</include>
          </includes>
     </fileSet>
     <fileSet filtered="true" encoding="UTF-8">
-        <directory>__artifactId__-impl/src/main/config</directory>
+        <directory>impl/src/test/java</directory>
+        <includes>
+            <include>**/*.java</include>
+         </includes>
+    </fileSet>
+    <fileSet filtered="true" encoding="UTF-8">
+        <directory>impl/src/main/config</directory>
         <includes>
             <include>**/*.xml</include>
          </includes>
     </fileSet>
     <fileSet filtered="true" encoding="UTF-8">
-       <directory>__artifactId__-impl/src/main/yang</directory>
+       <directory>impl/src/main/yang</directory>
        <includes>
          <include>**/*.yang</include>
        </includes>
      <!-- api -->
 
      <fileSet filtered="true" encoding="UTF-8">
-       <directory>__artifactId__-api</directory>
+       <directory>api</directory>
        <includes>
          <include>pom.xml</include>
        </includes>
      </fileSet>
      <fileSet filtered="true" encoding="UTF-8">
-       <directory>__artifactId__-api/src/main/yang</directory>
+       <directory>api/src/main/yang</directory>
        <includes>
          <include>**/*.yang</include>
        </includes>
@@ -93,7 +99,7 @@
 
      <!-- artifacts -->
      <fileSet filtered="true" encoding="UTF-8">
-       <directory>__artifactId__-artifacts</directory>
+       <directory>artifacts</directory>
        <includes>
          <include>pom.xml</include>
        </includes>
similarity index 97%
rename from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-features/pom.xml
rename to opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/features/pom.xml
index 49b43f442edba2810196bf470a146df77ba83a71..c5adb28db745ce6c676f21ccf3f10c4edd43f933 100644 (file)
@@ -26,6 +26,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
   <properties>
     <mdsal.version>1.2.0-SNAPSHOT</mdsal.version>
     <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
+    <configfile.directory>etc/opendaylight/karaf</configfile.directory>
   </properties>
   <dependencyManagement>
     <dependencies>
@@ -16,22 +16,22 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <repository>mvn:org.opendaylight.yangtools/features-yangtools/${symbol_dollar}{yangtools.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-mdsal/${symbol_dollar}{mdsal.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.controller/features-restconf/${symbol_dollar}{mdsal.version}/xml/features</repository>
-  <feature name='odl-${artifactId}-api' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId} :: api '>
+  <feature name='odl-${artifactId}-api' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId} :: api'>
     <feature version='${symbol_dollar}{yangtools.version}'>odl-yangtools-models</feature>
     <bundle>mvn:${groupId}/${artifactId}-api/${symbol_dollar}{project.version}</bundle>
   </feature>
-  <feature name='odl-${artifactId}-impl' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId} :: impl '>
+  <feature name='odl-${artifactId}' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId}'>
     <feature version='${symbol_dollar}{mdsal.version}'>odl-mdsal-broker</feature>
     <feature version='${symbol_dollar}{project.version}'>odl-${artifactId}-api</feature>
     <bundle>mvn:${groupId}/${artifactId}-impl/${symbol_dollar}{project.version}</bundle>
-    <configfile finalname="${artifactId}-impl-default-config.xml">mvn:${groupId}/${artifactId}-impl/${symbol_dollar}{project.version}/xml/config</configfile>
+    <configfile finalname="${configfile.directory}/${artifactId}.xml">mvn:${groupId}/${artifactId}-impl/${symbol_dollar}{project.version}/xml/config</configfile>
   </feature>
-  <feature name='odl-${artifactId}-impl-rest' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId} :: impl :: REST '>
-    <feature version="${symbol_dollar}{project.version}">odl-${artifactId}-impl</feature>
+  <feature name='odl-${artifactId}-rest' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId} :: REST'>
+    <feature version="${symbol_dollar}{project.version}">odl-${artifactId}</feature>
     <feature version="${symbol_dollar}{mdsal.version}">odl-restconf</feature>
   </feature>
-  <feature name='odl-${artifactId}-impl-ui' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId} :: impl :: UI'>
-    <feature version="${symbol_dollar}{project.version}">odl-${artifactId}-impl-rest</feature>
+  <feature name='odl-${artifactId}-ui' version='${symbol_dollar}{project.version}' description='OpenDaylight :: ${artifactId} :: UI'>
+    <feature version="${symbol_dollar}{project.version}">odl-${artifactId}-rest</feature>
     <feature version="${symbol_dollar}{mdsal.version}">odl-mdsal-apidocs</feature>
     <feature version="${symbol_dollar}{mdsal.version}">odl-mdsal-xsql</feature>
   </feature>
similarity index 80%
rename from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-impl/pom.xml
rename to opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/pom.xml
index 64d6834fef8ba708bbdbf1b9031d52b6333095e9..f9e77ed4b14302725170c73e86b2601bbda7c139 100644 (file)
@@ -29,6 +29,19 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>${artifactId}-api</artifactId>
       <version>${symbol_dollar}{project.version}</version>
     </dependency>
+
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>
@@ -20,7 +20,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <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:${artifactId}:impl">prefix:${artifactId}-impl</type>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:${artifactId}:impl">prefix:${artifactId}</type>
           <name>${artifactId}-default</name>
           <broker>
             <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
@@ -8,7 +8,7 @@
  * 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 ${package};
+package ${package}.impl;
 
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
  */
 package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210;
 
-import ${package}.${classPrefix}Provider;
+import ${package}.impl.${classPrefix}Provider;
 
-public class ${classPrefix}ImplModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210.Abstract${classPrefix}ImplModule {
-    public ${classPrefix}ImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+public class ${classPrefix}Module extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210.Abstract${classPrefix}Module {
+    public ${classPrefix}Module(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
 
-    public ${classPrefix}ImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210.${classPrefix}ImplModule oldModule, java.lang.AutoCloseable oldInstance) {
+    public ${classPrefix}Module(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210.${classPrefix}Module oldModule, java.lang.AutoCloseable oldInstance) {
         super(identifier, dependencyResolver, oldModule, oldInstance);
     }
 
@@ -18,6 +18,6 @@
 * Do not modify this file unless it is present under src/main directory
 */
 package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210;
-public class ${classPrefix}ImplModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210.Abstract${classPrefix}ImplModuleFactory {
+public class ${classPrefix}ModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210.Abstract${classPrefix}ModuleFactory {
 
 }
@@ -14,14 +14,14 @@ module ${artifactId}-impl {
             "Initial revision";
     }
 
-    identity ${artifactId}-impl {
+    identity ${artifactId} {
         base config:module-type;
-        config:java-name-prefix ${classPrefix}Impl;
+        config:java-name-prefix ${classPrefix};
     }
 
     augment "/config:modules/config:module/config:configuration" {
-        case ${artifactId}-impl {
-            when "/config:modules/config:module/config:type = '${artifactId}-impl'";
+        case ${artifactId} {
+            when "/config:modules/config:module/config:type = '${artifactId}'";
             container broker {
                 uses config:service-ref {
                     refine type {
diff --git a/opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/__packageInPathFormat__/impl/__classPrefix__ProviderTest.java b/opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/__packageInPathFormat__/impl/__classPrefix__ProviderTest.java
new file mode 100644 (file)
index 0000000..09b3dc4
--- /dev/null
@@ -0,0 +1,37 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+#set( $provider = "${classPrefix}Provider" )
+/*
+ * ${copyright} 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 ${package}.impl;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+
+import static org.mockito.Mockito.mock;
+
+public class ${classPrefix}ProviderTest {
+    @Test
+    public void testOnSessionInitiated() {
+        ${provider} provider = new ${provider}();
+
+        // ensure no exceptions
+        // currently this method is empty
+        provider.onSessionInitiated(mock(BindingAwareBroker.ProviderContext.class));
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        ${provider} provider = new ${provider}();
+
+        // ensure no exceptions
+        // currently this method is empty
+        provider.close();
+    }
+}
diff --git a/opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ModuleFactoryTest.java b/opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ModuleFactoryTest.java
new file mode 100644 (file)
index 0000000..9f8991f
--- /dev/null
@@ -0,0 +1,22 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+#set( $factory = "${classPrefix}ModuleFactory" )
+/*
+ * ${copyright} 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210;
+
+import org.junit.Test;
+
+public class ${classPrefix}ModuleFactoryTest {
+    @Test
+    public void testFactoryConstructor() {
+        // ensure no exceptions on construction
+        new ${factory}();
+    }
+}
diff --git a/opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ModuleTest.java b/opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/__artifactId__/impl/rev141210/__classPrefix__ModuleTest.java
new file mode 100644 (file)
index 0000000..bbef4d8
--- /dev/null
@@ -0,0 +1,58 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+#set( $module = "${classPrefix}Module" )
+/*
+ * ${copyright} 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${artifactId}.impl.rev141210;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.JmxAttribute;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import ${package}.impl.${classPrefix}Provider;
+
+import javax.management.ObjectName;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ${classPrefix}ModuleTest {
+    @Test
+    public void testCustomValidation() {
+        ${module} module = new ${module}(mock(ModuleIdentifier.class), mock(DependencyResolver.class));
+
+        // ensure no exceptions on validation
+        // currently this method is empty
+        module.customValidation();
+    }
+
+    @Test
+    public void testCreateInstance() throws Exception {
+        // configure mocks
+        DependencyResolver dependencyResolver = mock(DependencyResolver.class);
+        BindingAwareBroker broker = mock(BindingAwareBroker.class);
+        when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker);
+
+        // create instance of module with injected mocks
+        ${module} module = new ${module}(mock(ModuleIdentifier.class), dependencyResolver);
+
+        // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
+        AutoCloseable closeable = module.getInstance();
+
+        // verify that the module registered the returned provider with the broker
+        verify(broker).registerProvider((${classPrefix}Provider)closeable);
+
+        // ensure no exceptions on close
+        closeable.close();
+    }
+}
similarity index 77%
rename from opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/__artifactId__-karaf/pom.xml
rename to opendaylight/archetypes/opendaylight-startup/src/main/resources/archetype-resources/karaf/pom.xml
index 87b955c6b95c73233a4a475445b23f8dd74cbccb..486e3d39ba4ea58e610607517d61a9599272d707 100644 (file)
@@ -24,7 +24,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <maven>3.1.1</maven>
   </prerequisites>
   <properties>
-    <karaf.localFeature>odl-${artifactId}-impl-ui</karaf.localFeature>
+    <karaf.localFeature>odl-${artifactId}-ui</karaf.localFeature>
   </properties>
   <dependencyManagement>
     <dependencies>
@@ -54,4 +54,23 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <scope>runtime</scope>
     </dependency>
   </dependencies>
+  <!-- DO NOT install or deploy the karaf artifact -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 </project>
index 3221efd3628b833a1fd71622d4c1b942041c3e96..616704ada025601d9c0b069e6de3448bcea78bdf 100644 (file)
@@ -9,18 +9,18 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
   <groupId>${groupId}</groupId>
   <artifactId>${artifactId}-aggregator</artifactId>
   <version>${version}</version>
-  <name>${project.artifactId}</name>
+  <name>${artifactId}</name>
   <packaging>pom</packaging>
   <modelVersion>4.0.0</modelVersion>
   <prerequisites>
     <maven>3.1.1</maven>
   </prerequisites>
   <modules>
-    <module>${artifactId}-api</module>
-    <module>${artifactId}-impl</module>
-    <module>${artifactId}-karaf</module>
-    <module>${artifactId}-features</module>
-    <module>${artifactId}-artifacts</module>
+    <module>api</module>
+    <module>impl</module>
+    <module>karaf</module>
+    <module>features</module>
+    <module>artifacts</module>
   </modules>
   <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
   <build>
@@ -41,4 +41,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       </plugin>
     </plugins>
   </build>
+
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/${artifactId}.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/${artifactId}.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/${artifactId}:Main</url>
+  </scm>
 </project>
index 9a88e610072036b74e986947e73e19eb8ff0a10b..7a977f954555160062b6be7814d1331a8c4690c6 100644 (file)
@@ -15,7 +15,7 @@
 
   <properties>
 
-    <akka.version>2.3.4</akka.version>
+    <akka.version>2.3.9</akka.version>
     <appauth.version>0.5.0-SNAPSHOT</appauth.version>
     <archetype-app-northbound>0.1.0-SNAPSHOT</archetype-app-northbound>
     <arphandler.version>0.6.0-SNAPSHOT</arphandler.version>
@@ -81,6 +81,7 @@
     <!-- OpenEXI third party lib for netconf-->
     <exi.nagasena.version>0000.0002.0038.0</exi.nagasena.version>
     <felix.util.version>1.6.0</felix.util.version>
+    <features.test.version>1.5.0-SNAPSHOT</features.test.version>
     <filtervalve.version>1.5.0-SNAPSHOT</filtervalve.version>
     <findbugs.maven.plugin.version>2.4.0</findbugs.maven.plugin.version>
     <flowprogrammer.northbound.version>0.5.0-SNAPSHOT</flowprogrammer.northbound.version>
     <jmxGeneratorPath>src/main/yang-gen-config</jmxGeneratorPath>
     <jolokia-bridge.version>0.1.0-SNAPSHOT</jolokia-bridge.version>
     <jolokia.version>1.1.4</jolokia.version>
-    <jsr305.api.version>2.0.1</jsr305.api.version>
     <jsr311.api.version>1.1.1</jsr311.api.version>
     <jsr311.v2.api.version>2.0</jsr311.v2.api.version>
     <karaf.branding.version>1.1.0-SNAPSHOT</karaf.branding.version>
         <artifactId>java-concurrent-hash-trie-map</artifactId>
         <version>${ctrie.version}</version>
       </dependency>
-      <dependency>
-        <groupId>com.google.code.findbugs</groupId>
-        <artifactId>jsr305</artifactId>
-        <version>${jsr305.api.version}</version>
-      </dependency>
       <dependency>
         <groupId>com.google.code.gson</groupId>
         <artifactId>gson</artifactId>
 
       <!-- 3rd party dependencies needed by config-->
       <dependency>
-        <groupId>com.jcabi</groupId>
-        <artifactId>jcabi-maven-slf4j</artifactId>
-        <version>0.8</version>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-core</artifactId>
+        <version>3.1.1</version>
+        <scope>provided</scope>
       </dependency>
 
       <dependency>
         <version>${yangtools.version}</version>
         <scope>test</scope>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>features-test</artifactId>
+        <version>${features.test.version}</version>
+        <scope>test</scope>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>features-yangtools</artifactId>
index 5c9ed8767c38986587052ea5d588e3b079338979..3d72114dafbcd56d97f0d718d594c2b861dea99a 100644 (file)
@@ -66,23 +66,4 @@ public interface ConfigRegistry extends LookupRegistry, ServiceReferenceReadable
     Set<String> getAvailableModuleNames();
 
 
-
-    /**
-     * Find all runtime beans
-     *
-     * @return objectNames
-     */
-    Set<ObjectName> lookupRuntimeBeans();
-
-    /**
-     * Find all runtime of specified module
-     *
-     * @param moduleName
-     *            of bean
-     * @param instanceName
-     *            of bean
-     * @return objectNames
-     */
-    Set<ObjectName> lookupRuntimeBeans(String moduleName, String instanceName);
-
 }
index b90fc9c034753f467cd41a927c8afa3dbdf493a3..5d615c20845099d260cf5f2d0dddf5e6aad3d7bf 100644 (file)
@@ -71,4 +71,21 @@ public interface LookupRegistry {
      */
     Set<String> getAvailableModuleFactoryQNames();
 
+    /**
+     * Find all runtime beans
+     *
+     * @return objectNames
+     */
+    Set<ObjectName> lookupRuntimeBeans();
+
+    /**
+     * Find all runtime of specified module
+     *
+     * @param moduleName
+     *            of bean
+     * @param instanceName
+     *            of bean
+     * @return objectNames
+     */
+    Set<ObjectName> lookupRuntimeBeans(String moduleName, String instanceName);
 }
index 37c2e2d777d83004b43e9dbd32cb3e9793c61f36..186a7218bae75a8cf7c724b817f95b8f9d41be90 100644 (file)
@@ -482,6 +482,25 @@ class ConfigTransactionControllerImpl implements
     public void checkConfigBeanExists(ObjectName objectName) throws InstanceNotFoundException {
         txLookupRegistry.checkConfigBeanExists(objectName);
     }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<ObjectName> lookupRuntimeBeans() {
+        return txLookupRegistry.lookupRuntimeBeans();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<ObjectName> lookupRuntimeBeans(String moduleName,
+                                              String instanceName) {
+        return txLookupRegistry.lookupRuntimeBeans(moduleName, instanceName);
+    }
+
     // --
 
     /**
index f9a3801171a0064a2c43b28f297e66adfabf7498..a0138b2d9d8c270c2da2cdf1978874409c8e20c1 100644 (file)
@@ -116,6 +116,26 @@ class ConfigTransactionLookupRegistry  implements LookupRegistry, Closeable {
         return ModuleQNameUtil.getQNames(allCurrentFactories);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<ObjectName> lookupRuntimeBeans() {
+        return lookupRuntimeBeans("*", "*");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Set<ObjectName> lookupRuntimeBeans(String moduleName,
+                                              String instanceName) {
+        String finalModuleName = moduleName == null ? "*" : moduleName;
+        String finalInstanceName = instanceName == null ? "*" : instanceName;
+        ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern(
+                finalModuleName, finalInstanceName);
+        return transactionJMXRegistrator.queryNames(namePattern, null);
+    }
 
     @Override
     public String toString() {
index 27f0d5c1f287b60ab49eb679b8657a1f5b56c746..dd6c2b94222b67b6b0d04310993e83b435bdd436 100644 (file)
@@ -97,6 +97,16 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
                 throw new UnsupportedOperationException();
             }
 
+            @Override
+            public Set<ObjectName> lookupRuntimeBeans() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public Set<ObjectName> lookupRuntimeBeans(final String moduleName, final String instanceName) {
+                throw new UnsupportedOperationException();
+            }
+
             @Override
             public String toString() {
                 return "initial";
diff --git a/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/BeanReader.java b/opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/BeanReader.java
new file mode 100644 (file)
index 0000000..de9baa6
--- /dev/null
@@ -0,0 +1,10 @@
+package org.opendaylight.controller.config.util;
+
+import javax.management.ObjectName;
+
+/**
+ * Created by mmarsale on 20.2.2015.
+ */
+public interface BeanReader {
+    Object getAttributeCurrentValue(ObjectName on, String attributeName);
+}
index 99d46cb638c3255d59532f4018176720b51bd85b..d384ae55c00bda72566ca2742304d7419f787a1d 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.controller.config.util;
 import javax.management.ObjectName;
 import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
 
-public interface ConfigRegistryClient extends ConfigRegistryMXBean {
+public interface ConfigRegistryClient extends ConfigRegistryMXBean, BeanReader {
 
     ConfigTransactionClient createTransaction();
 
@@ -23,6 +23,4 @@ public interface ConfigRegistryClient extends ConfigRegistryMXBean {
     Object invokeMethod(ObjectName on, String name, Object[] params,
             String[] signature);
 
-    Object getAttributeCurrentValue(ObjectName on, String attributeName);
-
 }
index 099d010642ee510052a43ade62b77e2e20f2a884..a39111afee11168fe2250e84388e56d84f52b8be 100644 (file)
@@ -211,7 +211,7 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient {
         } catch (AttributeNotFoundException | InstanceNotFoundException
                 | MBeanException | ReflectionException e) {
             throw new RuntimeException("Unable to get attribute "
-                    + attributeName + " for " + on, e);
+                    + attributeName + " for " + on + ". Available beans: " + lookupConfigBeans(), e);
         }
     }
 
index 359035d51dd57aebc9762ba27d5e272eeb80ceea..c7c072d39d8233e84d6f93ebd585f759114a833b 100644 (file)
@@ -16,7 +16,7 @@ import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
 
 public interface ConfigTransactionClient extends
-        ConfigTransactionControllerMXBean {
+        ConfigTransactionControllerMXBean, BeanReader {
 
     CommitStatus commit() throws ConflictingVersionException,
             ValidationException;
@@ -47,7 +47,7 @@ public interface ConfigTransactionClient extends
      * @param on - ObjectName of the Object from which the attribute should be read
      * @param jmxName - name of the attribute to be read
      *
-     * @return Attribute of Object on with attribute name jmxName
+     * @return Object of Object on with attribute name jmxName
      */
     Attribute getAttribute(ObjectName on, String jmxName);
 }
index a0af19796ebedfa5bedc809a5ce18f3b23d5858e..26ca1391ad4bf32eea9708e2db47f21cc33bdcfa 100644 (file)
@@ -240,6 +240,26 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
         configTransactionControllerMXBeanProxy.checkServiceReferenceExists(objectName);
     }
 
+    @Override
+    public Attribute getAttribute(ObjectName on, String attrName) {
+        if (ObjectNameUtil.getTransactionName(on) == null) {
+            throw new IllegalArgumentException("Not in transaction instance "
+                    + on + ", no transaction name present");
+        }
+
+        try {
+            return new Attribute(attrName, configMBeanServer.getAttribute(on,attrName));
+        } catch (JMException e) {
+            throw new IllegalStateException("Unable to get attribute "
+                    + attrName + " for " + on, e);
+        }
+    }
+
+    @Override
+    public Object getAttributeCurrentValue(ObjectName on, String attrName) {
+        return getAttribute(on, attrName).getValue();
+    }
+
     @Override
     public void validateBean(ObjectName configBeanON)
             throws ValidationException {
@@ -273,22 +293,17 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
     }
 
     @Override
-    public Attribute getAttribute(ObjectName on, String attrName) {
-        if (ObjectNameUtil.getTransactionName(on) == null) {
-            throw new IllegalArgumentException("Not in transaction instance "
-                    + on + ", no transaction name present");
-        }
+    public Set<String> getAvailableModuleFactoryQNames() {
+        return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames();
+    }
 
-        try {
-            return new Attribute(attrName, configMBeanServer.getAttribute(on,attrName));
-        } catch (JMException e) {
-            throw new IllegalStateException("Unable to get attribute "
-                    + attrName + " for " + on, e);
-        }
+    @Override
+    public Set<ObjectName> lookupRuntimeBeans() {
+        return configTransactionControllerMXBeanProxy.lookupRuntimeBeans();
     }
 
     @Override
-    public Set<String> getAvailableModuleFactoryQNames() {
-        return configTransactionControllerMXBeanProxy.getAvailableModuleFactoryQNames();
+    public Set<ObjectName> lookupRuntimeBeans(final String moduleName, final String instanceName) {
+        return configTransactionControllerMXBeanProxy.lookupRuntimeBeans(moduleName, instanceName);
     }
 }
index e1138addc74bd9a6d2072b80d93fe98263a46ffc..e69019405dec6e1be983c153eeab7efbe126d2da 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.config.util;
 
 import com.google.common.collect.Sets;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -184,6 +185,16 @@ public class TestingConfigTransactionController implements
         return Sets.newHashSet("availableModuleFactoryQNames");
     }
 
+    @Override
+    public Set<ObjectName> lookupRuntimeBeans() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<ObjectName> lookupRuntimeBeans(final String moduleName, final String instanceName) {
+        return Collections.emptySet();
+    }
+
     @Override
     public ObjectName getServiceReference(String serviceInterfaceQName, String refName) throws InstanceNotFoundException {
         return conf3;
index 6c8a591bb8a7a7db03fb1564c3d7f93c66595995..ae190848c9f136543e30521a153ba24d7d42c64f 100644 (file)
       <artifactId>guava</artifactId>
     </dependency>
 
-    <dependency>
-      <groupId>com.jcabi</groupId>
-      <artifactId>jcabi-maven-slf4j</artifactId>
-    </dependency>
-
     <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
       <artifactId>commons-lang3</artifactId>
     </dependency>
 
-    <dependency>
-      <groupId>org.codehaus.gmaven.runtime</groupId>
-      <artifactId>gmaven-runtime-2.0</artifactId>
-      <exclusions>
-        <exclusion>
-          <groupId>org.sonatype.gossip</groupId>
-          <artifactId>gossip</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>yang-jmx-generator</artifactId>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-maven-plugin-spi</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-core</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>org.slf4j</groupId>
index 9ad8d2826f81e444e6cbf4efaea6d31be3bb3bc9..1f1776f0a5f86ffa1f229de339a8463ebcb2a9b0 100644 (file)
@@ -23,7 +23,6 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.commons.io.FileUtils;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
@@ -35,42 +34,54 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang2sources.spi.CodeGenerator;
+import org.opendaylight.yangtools.yang2sources.spi.BasicCodeGenerator;
+import org.opendaylight.yangtools.yang2sources.spi.MavenProjectAware;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.slf4j.impl.StaticLoggerBinder;
 
 /**
  * This class interfaces with yang-maven-plugin. Gets parsed yang modules in
  * {@link SchemaContext}, and parameters form the plugin configuration, and
  * writes service interfaces and/or modules.
  */
-public class JMXGenerator implements CodeGenerator {
+public class JMXGenerator implements BasicCodeGenerator, MavenProjectAware {
+    private static final class NamespaceMapping {
+        private final String namespace, packageName;
 
+        public NamespaceMapping(final String namespace, final String packagename) {
+            this.namespace = namespace;
+            this.packageName = packagename;
+        }
+    }
+
+    @VisibleForTesting
     static final String NAMESPACE_TO_PACKAGE_DIVIDER = "==";
+    @VisibleForTesting
     static final String NAMESPACE_TO_PACKAGE_PREFIX = "namespaceToPackage";
+    @VisibleForTesting
     static final String MODULE_FACTORY_FILE_BOOLEAN = "moduleFactoryFile";
 
+    private static final Logger LOG = LoggerFactory.getLogger(JMXGenerator.class);
+    private static final Pattern NAMESPACE_MAPPING_PATTERN = Pattern.compile("(.+)" + NAMESPACE_TO_PACKAGE_DIVIDER + "(.+)");
+
     private PackageTranslator packageTranslator;
     private final CodeWriter codeWriter;
-    private static final Logger LOG = LoggerFactory
-            .getLogger(JMXGenerator.class);
     private Map<String, String> namespaceToPackageMapping;
     private File resourceBaseDir;
     private File projectBaseDir;
     private boolean generateModuleFactoryFile = true;
 
     public JMXGenerator() {
-        this.codeWriter = new CodeWriter();
+        this(new CodeWriter());
     }
 
-    public JMXGenerator(CodeWriter codeWriter) {
+    public JMXGenerator(final CodeWriter codeWriter) {
         this.codeWriter = codeWriter;
     }
 
     @Override
-    public Collection<File> generateSources(SchemaContext context,
-                                            File outputBaseDir, Set<Module> yangModulesInCurrentMavenModule) {
+    public Collection<File> generateSources(final SchemaContext context,
+                                            final File outputBaseDir, final Set<Module> yangModulesInCurrentMavenModule) {
 
         Preconditions.checkArgument(context != null, "Null context received");
         Preconditions.checkArgument(outputBaseDir != null,
@@ -173,7 +184,8 @@ public class JMXGenerator implements CodeGenerator {
         return generatedFiles.getFiles();
     }
 
-    static File concatFolders(File projectBaseDir, String... folderNames) {
+    @VisibleForTesting
+    static File concatFolders(final File projectBaseDir, final String... folderNames) {
         StringBuilder b = new StringBuilder();
         for (String folder : folderNames) {
             b.append(folder);
@@ -183,18 +195,14 @@ public class JMXGenerator implements CodeGenerator {
     }
 
     @Override
-    public void setAdditionalConfig(Map<String, String> additionalCfg) {
-        if (LOG != null) {
-            LOG.debug(getClass().getCanonicalName(),
-                    ": Additional configuration received: ",
-                    additionalCfg.toString());
-        }
+    public void setAdditionalConfig(final Map<String, String> additionalCfg) {
+        LOG.debug("{}: Additional configuration received: {}", getClass().getCanonicalName(), additionalCfg);
         this.namespaceToPackageMapping = extractNamespaceMapping(additionalCfg);
         this.generateModuleFactoryFile = extractModuleFactoryBoolean(additionalCfg);
     }
 
     private boolean extractModuleFactoryBoolean(
-            Map<String, String> additionalCfg) {
+            final Map<String, String> additionalCfg) {
         String bool = additionalCfg.get(MODULE_FACTORY_FILE_BOOLEAN);
         if (bool == null) {
             return true;
@@ -205,13 +213,8 @@ public class JMXGenerator implements CodeGenerator {
         return true;
     }
 
-    @Override
-    public void setLog(Log log) {
-        StaticLoggerBinder.getSingleton().setMavenLog(log);
-    }
-
     private static Map<String, String> extractNamespaceMapping(
-            Map<String, String> additionalCfg) {
+            final Map<String, String> additionalCfg) {
         Map<String, String> namespaceToPackage = Maps.newHashMap();
         for (String key : additionalCfg.keySet()) {
             if (key.startsWith(NAMESPACE_TO_PACKAGE_PREFIX)) {
@@ -224,46 +227,30 @@ public class JMXGenerator implements CodeGenerator {
         return namespaceToPackage;
     }
 
-    static Pattern namespaceMappingPattern = Pattern.compile("(.+)"
-            + NAMESPACE_TO_PACKAGE_DIVIDER + "(.+)");
-
-    private static NamespaceMapping extractNamespaceMapping(String mapping) {
-        Matcher matcher = namespaceMappingPattern.matcher(mapping);
-        Preconditions
-                .checkArgument(matcher.matches(), String.format("Namespace to package mapping:%s is in invalid " +
-                        "format, requested format is: %s", mapping, namespaceMappingPattern));
+    private static NamespaceMapping extractNamespaceMapping(final String mapping) {
+        Matcher matcher = NAMESPACE_MAPPING_PATTERN.matcher(mapping);
+        Preconditions.checkArgument(matcher.matches(),
+            "Namespace to package mapping:%s is in invalid format, requested format is: %s",
+            mapping, NAMESPACE_MAPPING_PATTERN);
         return new NamespaceMapping(matcher.group(1), matcher.group(2));
     }
 
-    private static class NamespaceMapping {
-        public NamespaceMapping(String namespace, String packagename) {
-            this.namespace = namespace;
-            this.packageName = packagename;
-        }
-
-        private final String namespace, packageName;
-    }
-
     @Override
-    public void setResourceBaseDir(File resourceDir) {
+    public void setResourceBaseDir(final File resourceDir) {
         this.resourceBaseDir = resourceDir;
     }
 
     @Override
-    public void setMavenProject(MavenProject project) {
+    public void setMavenProject(final MavenProject project) {
         this.projectBaseDir = project.getBasedir();
-
-        if (LOG != null) {
-            LOG.debug(getClass().getCanonicalName(), " project base dir: ",
-                    projectBaseDir);
-        }
+        LOG.debug("{}: project base dir: {}", getClass().getCanonicalName(), projectBaseDir);
     }
 
     @VisibleForTesting
     static class GeneratedFilesTracker {
         private final Set<File> files = Sets.newHashSet();
 
-        void addFile(File file) {
+        void addFile(final File file) {
             if (files.contains(file)) {
                 List<File> undeletedFiles = Lists.newArrayList();
                 for (File presentFile : files) {
@@ -283,7 +270,7 @@ public class JMXGenerator implements CodeGenerator {
             files.add(file);
         }
 
-        void addFile(Collection<File> files) {
+        void addFile(final Collection<File> files) {
             for (File file : files) {
                 addFile(file);
             }
index 19e875f9b1805f851322e82ebb565752c9d710cc..00454d8acf14507a518e63b5d71b79020ce89bfd 100644 (file)
@@ -48,9 +48,9 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Meth
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDefinition;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
-import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
 
 public class TemplateFactory {
 
@@ -59,7 +59,7 @@ public class TemplateFactory {
      * bean as value that should be persisted from this instance.
      */
     public static Map<String, FtlTemplate> getTOAndMXInterfaceFtlFiles(
-            RuntimeBeanEntry entry) {
+            final RuntimeBeanEntry entry) {
         Map<String, FtlTemplate> result = new HashMap<>();
         { // create GeneralInterfaceFtlFile for runtime MXBean. Attributes will
           // be transformed to getter methods
@@ -109,7 +109,7 @@ public class TemplateFactory {
     }
 
     // FIXME: put into Type.toString
-    static String serializeType(Type type, boolean addWildcards) {
+    static String serializeType(final Type type, final boolean addWildcards) {
         if (type instanceof ParameterizedType){
             ParameterizedType parameterizedType = (ParameterizedType) type;
             StringBuilder sb = new StringBuilder();
@@ -131,11 +131,11 @@ public class TemplateFactory {
         }
     }
 
-    static String serializeType(Type type) {
+    static String serializeType(final Type type) {
         return serializeType(type, false);
     }
 
-    private static String getReturnType(AttributeIfc attributeIfc) {
+    private static String getReturnType(final AttributeIfc attributeIfc) {
         String returnType;
         if (attributeIfc instanceof TypedAttribute) {
             Type type = ((TypedAttribute) attributeIfc).getType();
@@ -151,7 +151,7 @@ public class TemplateFactory {
     }
 
     public static GeneralInterfaceTemplate serviceInterfaceFromSie(
-            ServiceInterfaceEntry sie) {
+            final ServiceInterfaceEntry sie) {
 
         List<String> extendedInterfaces = Lists
                 .newArrayList(AbstractServiceInterface.class.getCanonicalName());
@@ -177,7 +177,7 @@ public class TemplateFactory {
     }
 
     public static AbstractFactoryTemplate abstractFactoryTemplateFromMbe(
-            ModuleMXBeanEntry mbe) {
+            final ModuleMXBeanEntry mbe) {
         AbstractFactoryAttributesProcessor attrProcessor = new AbstractFactoryAttributesProcessor();
         attrProcessor.processAttributes(mbe.getAttributes(),
                 mbe.getPackageName());
@@ -191,7 +191,7 @@ public class TemplateFactory {
     }
 
     public static AbstractModuleTemplate abstractModuleTemplateFromMbe(
-            ModuleMXBeanEntry mbe) {
+            final ModuleMXBeanEntry mbe) {
         AbstractModuleAttributesProcessor attrProcessor = new AbstractModuleAttributesProcessor(mbe.getAttributes());
 
         List<ModuleField> moduleFields = attrProcessor.getModuleFields();
@@ -234,7 +234,7 @@ public class TemplateFactory {
     }
 
     public static StubFactoryTemplate stubFactoryTemplateFromMbe(
-            ModuleMXBeanEntry mbe) {
+            final ModuleMXBeanEntry mbe) {
         return new StubFactoryTemplate(getHeaderFromEntry(mbe),
                 mbe.getPackageName(), mbe.getStubFactoryName(),
                 mbe.getFullyQualifiedName(mbe.getAbstractFactoryName())
@@ -242,7 +242,7 @@ public class TemplateFactory {
     }
 
     public static GeneralInterfaceTemplate mXBeanInterfaceTemplateFromMbe(
-            ModuleMXBeanEntry mbe) {
+            final ModuleMXBeanEntry mbe) {
         MXBeanInterfaceAttributesProcessor attrProcessor = new MXBeanInterfaceAttributesProcessor();
         attrProcessor.processAttributes(mbe.getAttributes());
         GeneralInterfaceTemplate ifcTemplate = new GeneralInterfaceTemplate(
@@ -254,7 +254,7 @@ public class TemplateFactory {
     }
 
     public static Map<String, GeneralClassTemplate> tOsFromMbe(
-            ModuleMXBeanEntry mbe) {
+            final ModuleMXBeanEntry mbe) {
         Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
         TOAttributesProcessor processor = new TOAttributesProcessor();
         processor.processAttributes(mbe.getAttributes());
@@ -275,7 +275,7 @@ public class TemplateFactory {
     }
 
     public static Map<String, GeneralClassTemplate> tOsFromRbe(
-            RuntimeBeanEntry rbe) {
+            final RuntimeBeanEntry rbe) {
         Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
         TOAttributesProcessor processor = new TOAttributesProcessor();
         Map<String, AttributeIfc> yangPropertiesToTypesMap = Maps.newHashMap(rbe.getYangPropertiesToTypesMap());
@@ -316,7 +316,7 @@ public class TemplateFactory {
         return retVal;
     }
 
-    private static Header getHeaderFromEntry(AbstractEntry mbe) {
+    private static Header getHeaderFromEntry(final AbstractEntry mbe) {
         return new Header(mbe.getYangModuleName(), mbe.getYangModuleLocalname());
     }
 
@@ -326,7 +326,7 @@ public class TemplateFactory {
 
         private final List<TOInternal> tos = Lists.newArrayList();
 
-        void processAttributes(Map<String, AttributeIfc> attributes) {
+        void processAttributes(final Map<String, AttributeIfc> attributes) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 AttributeIfc attributeIfc = attrEntry.getValue();
                 if (attributeIfc instanceof TOAttribute) {
@@ -342,7 +342,7 @@ public class TemplateFactory {
             }
         }
 
-        private void createTOInternal(TOAttribute toAttribute) {
+        private void createTOInternal(final TOAttribute toAttribute) {
 
             Map<String, AttributeIfc> attrs = toAttribute.getCapitalizedPropertiesToTypesMap();
             // recursive processing of TO's attributes
@@ -360,12 +360,12 @@ public class TemplateFactory {
             private List<Field> fields;
             private List<MethodDefinition> methods;
 
-            public TOInternal(Type type, Map<String, AttributeIfc> attrs) {
+            public TOInternal(final Type type, final Map<String, AttributeIfc> attrs) {
                 this(type.getFullyQualifiedName(), type.getName(), attrs, type.getPackageName());
             }
 
-            public TOInternal(String fullyQualifiedName, String name,
-                    Map<String, AttributeIfc> attrs, String packageName) {
+            public TOInternal(final String fullyQualifiedName, final String name,
+                    final Map<String, AttributeIfc> attrs, final String packageName) {
                 this.fullyQualifiedName = fullyQualifiedName;
                 this.name = name;
                 processAttrs(attrs, packageName);
@@ -374,7 +374,7 @@ public class TemplateFactory {
             private final static String dependencyResolverVarName = "dependencyResolver";
             private final static String dependencyResolverInjectMethodName = "injectDependencyResolver";
 
-            private void processAttrs(Map<String, AttributeIfc> attrs, String packageName) {
+            private void processAttrs(final Map<String, AttributeIfc> attrs, final String packageName) {
                 fields = Lists.newArrayList();
                 methods = Lists.newArrayList();
 
@@ -386,8 +386,7 @@ public class TemplateFactory {
 
                 for (Entry<String, AttributeIfc> attrEntry : attrs.entrySet()) {
                     String innerName = attrEntry.getKey();
-                    String varName = BindingGeneratorUtil
-                            .parseToValidParamName(attrEntry.getKey());
+                    String varName = BindingMapping.getPropertyName(attrEntry.getKey());
 
                     String fullyQualifiedName, nullableDefault = null;
                     if (attrEntry.getValue() instanceof TypedAttribute) {
@@ -449,7 +448,7 @@ public class TemplateFactory {
     private static class MXBeanInterfaceAttributesProcessor {
         private final List<MethodDeclaration> methods = Lists.newArrayList();
 
-        void processAttributes(Map<String, AttributeIfc> attributes) {
+        void processAttributes(final Map<String, AttributeIfc> attributes) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 String returnType;
                 AttributeIfc attributeIfc = attrEntry.getValue();
@@ -473,8 +472,7 @@ public class TemplateFactory {
                 MethodDeclaration getter = new MethodDeclaration(returnType,
                         getterName, Collections.<Field> emptyList());
 
-                String varName = BindingGeneratorUtil
-                        .parseToValidParamName(attrEntry.getKey());
+                String varName = BindingMapping.getPropertyName(attrEntry.getKey());
                 String setterName = "set"
                         + attributeIfc.getUpperCaseCammelCase();
                 MethodDeclaration setter = new MethodDeclaration("void",
@@ -519,8 +517,8 @@ public class TemplateFactory {
 
         private final List<Field> fields = Lists.newArrayList();
 
-        void processAttributes(Map<String, AttributeIfc> attributes,
-                String packageName) {
+        void processAttributes(final Map<String, AttributeIfc> attributes,
+                final String packageName) {
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
                 String type;
                 String nullableDefaultWrapped = null;
@@ -550,7 +548,7 @@ public class TemplateFactory {
             private final List<ModuleField> moduleFields;
             private final List<MethodDefinition> methods;
 
-            private Holder(List<ModuleField> moduleFields, List<MethodDefinition> methods) {
+            private Holder(final List<ModuleField> moduleFields, final List<MethodDefinition> methods) {
                 this.moduleFields = Collections.unmodifiableList(moduleFields);
                 this.methods = Collections.unmodifiableList(methods);
             }
@@ -559,11 +557,11 @@ public class TemplateFactory {
         private final Holder holder;
 
 
-        private AbstractModuleAttributesProcessor(Map<String, AttributeIfc> attributes) {
+        private AbstractModuleAttributesProcessor(final Map<String, AttributeIfc> attributes) {
             this.holder = processAttributes(attributes);
         }
 
-        private static Holder processAttributes(Map<String, AttributeIfc> attributes) {
+        private static Holder processAttributes(final Map<String, AttributeIfc> attributes) {
             List<ModuleField> moduleFields = new ArrayList<>();
             List<MethodDefinition> methods = new ArrayList<>();
             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
@@ -607,8 +605,7 @@ public class TemplateFactory {
                     }
                 }
 
-                String varName = BindingGeneratorUtil
-                        .parseToValidParamName(attrEntry.getKey());
+                String varName = BindingMapping.getPropertyName(attrEntry.getKey());
 
                 ModuleField field;
                 if (isIdentity) {
@@ -689,7 +686,7 @@ public class TemplateFactory {
     }
 
 
-    private static boolean needsDepResolver(AttributeIfc value) {
+    private static boolean needsDepResolver(final AttributeIfc value) {
         if(value instanceof TOAttribute) {
             return true;
         }
@@ -701,7 +698,7 @@ public class TemplateFactory {
         return false;
     }
 
-    private static String getInnerTypeFromIdentity(Type type) {
+    private static String getInnerTypeFromIdentity(final Type type) {
         Preconditions.checkArgument(type instanceof ParameterizedType);
         Type[] args = ((ParameterizedType) type).getActualTypeArguments();
         Preconditions.checkArgument(args.length ==1);
index a6cfc58c34e96a06626393c49774dcf504c5e5b8..3dae004161fc414b7c1619e0915b539c9762c9e5 100644 (file)
@@ -16,11 +16,8 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
@@ -42,7 +39,6 @@ import java.util.Set;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import org.apache.commons.io.FileUtils;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.compiler.IProblem;
@@ -124,13 +120,6 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         File targetDir = new File(generatorOutputPath, "target");
         generatedResourcesDir = new File(targetDir, "generated-resources");
         jmxGenerator.setResourceBaseDir(generatedResourcesDir);
-        Log mockedLog = mock(Log.class);
-        doReturn(false).when(mockedLog).isDebugEnabled();
-        doNothing().when(mockedLog).debug(any(CharSequence.class));
-        doNothing().when(mockedLog).info(any(CharSequence.class));
-        doNothing().when(mockedLog).error(any(CharSequence.class),
-                any(Throwable.class));
-        jmxGenerator.setLog(mockedLog);
         MavenProject project = mock(MavenProject.class);
         doReturn(generatorOutputPath).when(project).getBasedir();
         jmxGenerator.setMavenProject(project);
@@ -158,18 +147,19 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         verifyModuleFactoryFile(false);
     }
 
-    private void verifyModuleFactoryFile(boolean shouldBePresent) {
+    private void verifyModuleFactoryFile(final boolean shouldBePresent) {
         File factoryFile = new File(generatedResourcesDir, "META-INF"
                 + File.separator + "services" + File.separator
                 + ModuleFactory.class.getName());
-        if (!shouldBePresent)
+        if (!shouldBePresent) {
             assertFalse("Factory file should not be generated",
                     factoryFile.exists());
-        else
+        } else {
             assertTrue("Factory file should be generated", factoryFile.exists());
+        }
     }
 
-    public static List<String> toFileNames(Collection<File> files) {
+    public static List<String> toFileNames(final Collection<File> files) {
         List<String> result = new ArrayList<>();
         for (File f : files) {
             result.add(f.getName());
@@ -279,7 +269,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 new Predicate<File>() {
 
                     @Override
-                    public boolean apply(File input) {
+                    public boolean apply(final File input) {
                         return input.getName().endsWith("xml");
                     }
                 });
@@ -288,7 +278,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 new Predicate<File>() {
 
                     @Override
-                    public boolean apply(File input) {
+                    public boolean apply(final File input) {
                         return input.getName().endsWith("java");
                     }
                 });
@@ -303,16 +293,21 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
             String name = file.getName();
             MbeASTVisitor visitor = new MbeASTVisitor();
             verifiers.put(name, visitor);
-            if (name.equals("AbstractDynamicThreadPoolModule.java"))
+            if (name.equals("AbstractDynamicThreadPoolModule.java")) {
                 abstractDynamicThreadPoolModuleVisitor = visitor;
-            if (name.equals("AsyncEventBusModuleMXBean.java"))
+            }
+            if (name.equals("AsyncEventBusModuleMXBean.java")) {
                 asyncEventBusModuleMXBeanVisitor = visitor;
-            if (name.equals("AbstractNamingThreadFactoryModuleFactory.java"))
+            }
+            if (name.equals("AbstractNamingThreadFactoryModuleFactory.java")) {
                 abstractNamingThreadFactoryModuleFactoryVisitor = visitor;
-            if (name.equals("AsyncEventBusModule.java"))
+            }
+            if (name.equals("AsyncEventBusModule.java")) {
                 asyncEventBusModuleVisitor = visitor;
-            if (name.equals("EventBusModuleFactory.java"))
+            }
+            if (name.equals("EventBusModuleFactory.java")) {
                 eventBusModuleFactoryVisitor = visitor;
+            }
         }
 
         processGeneratedCode(javaFiles, verifiers);
@@ -348,25 +343,25 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     }
 
-    private void verifyXmlFiles(Collection<File> xmlFiles) throws Exception {
+    private void verifyXmlFiles(final Collection<File> xmlFiles) throws Exception {
         ErrorHandler errorHandler = new ErrorHandler() {
 
             @Override
-            public void warning(SAXParseException exception)
+            public void warning(final SAXParseException exception)
                     throws SAXException {
                 fail("Generated blueprint xml is not well formed "
                         + exception.getMessage());
             }
 
             @Override
-            public void fatalError(SAXParseException exception)
+            public void fatalError(final SAXParseException exception)
                     throws SAXException {
                 fail("Generated blueprint xml is not well formed "
                         + exception.getMessage());
             }
 
             @Override
-            public void error(SAXParseException exception) throws SAXException {
+            public void error(final SAXParseException exception) throws SAXException {
                 fail("Generated blueprint xml is not well formed "
                         + exception.getMessage());
             }
@@ -386,7 +381,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     }
 
-    private void assertEventBusModuleFactory(MbeASTVisitor visitor) {
+    private void assertEventBusModuleFactory(final MbeASTVisitor visitor) {
         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
                 + ".threads.java", visitor.packageName);
         assertEquals("EventBusModuleFactory", visitor.type);
@@ -406,7 +401,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 visitor.methodJavadoc.size());
     }
 
-    private void assertAsyncEventBusModule(MbeASTVisitor visitor) {
+    private void assertAsyncEventBusModule(final MbeASTVisitor visitor) {
         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
                 + ".threads.java", visitor.packageName);
         assertEquals("AsyncEventBusModule", visitor.type);
@@ -427,7 +422,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
     }
 
     private void assertAbstractNamingThreadFactoryModuleFactory(
-            MbeASTVisitor visitor) {
+            final MbeASTVisitor visitor) {
         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
                 + ".threads.java", visitor.packageName);
         assertEquals("AbstractNamingThreadFactoryModuleFactory", visitor.type);
@@ -450,7 +445,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     }
 
-    private void assertFactoryMethods(Set<String> methods, int expectedSize) {
+    private void assertFactoryMethods(final Set<String> methods, final int expectedSize) {
 
         List<ArgumentAssertion> args = Lists.newArrayList();
         ArgumentAssertion oldInstanceArg = new ArgumentAssertion(DynamicMBeanWithInstance.class.getCanonicalName(), "old");
@@ -496,12 +491,12 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     }
 
-    private void assertMethodPresent(Set<String> methods, MethodAssertion methodAssertion) {
+    private void assertMethodPresent(final Set<String> methods, final MethodAssertion methodAssertion) {
         assertTrue(String.format("Generated methods did not contain %s, generated methods: %s",
                 methodAssertion.toString(), methods), methods.contains(methodAssertion.toString()));
     }
 
-    private void assertAsyncEventBusModuleMXBean(MbeASTVisitor visitor) {
+    private void assertAsyncEventBusModuleMXBean(final MbeASTVisitor visitor) {
         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
                 + ".threads.java", visitor.packageName);
         assertEquals("AsyncEventBusModuleMXBean", visitor.type);
@@ -511,7 +506,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     }
 
-    private void assertAbstractDynamicThreadPoolModule(MbeASTVisitor visitor) {
+    private void assertAbstractDynamicThreadPoolModule(final MbeASTVisitor visitor) {
         assertEquals(PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
                 + ".threads.java", visitor.packageName);
         assertNotNull(visitor.javadoc);
@@ -557,8 +552,8 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 visitor.methodJavadoc.get("void setMaximumSize(java.lang.Long maximumSize)"));
     }
 
-    private void assertDeclaredField(Set<String> fieldDeclarations,
-            String declaration) {
+    private void assertDeclaredField(final Set<String> fieldDeclarations,
+            final String declaration) {
         assertTrue("Missing field " + declaration + ", got: "
                 + fieldDeclarations,
                 fieldDeclarations.contains(declaration + ";\n"));
@@ -570,13 +565,13 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         protected Map<String, String> methodDescriptions = Maps.newHashMap();
 
         @Override
-        public boolean visit(PackageDeclaration node) {
+        public boolean visit(final PackageDeclaration node) {
             packageName = node.getName().toString();
             return super.visit(node);
         }
 
         @Override
-        public boolean visit(NormalAnnotation node) {
+        public boolean visit(final NormalAnnotation node) {
             if (node.getTypeName().toString()
                     .equals(Description.class.getCanonicalName())) {
                 if (node.getParent() instanceof TypeDeclaration) {
@@ -604,7 +599,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         }
 
         @Override
-        public boolean visit(TypeDeclaration node) {
+        public boolean visit(final TypeDeclaration node) {
             javadoc = node.getJavadoc() == null ? null : node.getJavadoc()
                     .toString();
             type = node.getName().toString();
@@ -624,7 +619,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         private final Map<String, String> methodJavadoc = Maps.newHashMap();
 
         @Override
-        public boolean visit(NormalAnnotation node) {
+        public boolean visit(final NormalAnnotation node) {
             boolean result = super.visit(node);
             if (node.getTypeName().toString()
                     .equals(RequireInterface.class.getCanonicalName())
@@ -638,16 +633,16 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         }
 
         @Override
-        public boolean visit(FieldDeclaration node) {
+        public boolean visit(final FieldDeclaration node) {
             fieldDeclarations.add(node.toString());
             return super.visit(node);
         }
 
         @Override
-        public boolean visit(MethodDeclaration node) {
-            if (node.isConstructor())
+        public boolean visit(final MethodDeclaration node) {
+            if (node.isConstructor()) {
                 constructors.add(node.toString());
-            else {
+            else {
                 String methodSignature = node.getReturnType2() + " " + node.getName() + "(";
                 boolean first = true;
                 for (Object o : node.parameters()) {
@@ -668,7 +663,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
         }
 
         @Override
-        public boolean visit(TypeDeclaration node) {
+        public boolean visit(final TypeDeclaration node) {
             boolean visit = super.visit(node);
             List<?> superIfcs = node.superInterfaceTypes();
             implmts = superIfcs != null && !superIfcs.isEmpty() ? superIfcs
@@ -680,14 +675,14 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     }
 
-    private void assertContains(String source, String... contained) {
+    private void assertContains(final String source, final String... contained) {
         for (String string : contained) {
             assertThat(source, containsString(string));
         }
     }
 
-    private void processGeneratedCode(Collection<File> files,
-            Map<String, ASTVisitor> verifiers) throws IOException {
+    private void processGeneratedCode(final Collection<File> files,
+            final Map<String, ASTVisitor> verifiers) throws IOException {
         ASTParser parser = ASTParser.newParser(AST.JLS3);
         Map<?, ?> options = JavaCore.getOptions();
         JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, options);
@@ -705,27 +700,31 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
             for (IProblem c : cu.getProblems()) {
                 // 1610613332 = Syntax error, annotations are only available if
                 // source level is 5.0
-                if (c.getID() == 1610613332)
+                if (c.getID() == 1610613332) {
                     continue;
+                }
                 // 1610613332 = Syntax error, parameterized types are only
                 // available if source level is 5.0
-                if (c.getID() == 1610613329)
+                if (c.getID() == 1610613329) {
                     continue;
-                if (c.getID() == 1610613328) // 'for each' statements are only available if source level is 5.0
+                }
+                if (c.getID() == 1610613328) {
                     continue;
+                }
                 fail("Error in generated source code " + file + ":"
                         + c.getSourceLineNumber() + " id: " + c.getID() + " message:"  + c.toString());
             }
 
             ASTVisitor visitor = verifiers.get(file.getName());
-            if (visitor == null)
+            if (visitor == null) {
                 fail("Unknown generated file " + file.getName());
+            }
             cu.accept(visitor);
 
         }
     }
 
-    public static char[] readFileAsChars(File file) throws IOException {
+    public static char[] readFileAsChars(final File file) throws IOException {
         List<String> readLines = Files
                 .readLines(file, Charset.forName("utf-8"));
         char[] retVal = new char[0];
@@ -741,15 +740,15 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     private static class MethodAssertion extends ArgumentAssertion{
 
-        private List<ArgumentAssertion> arguments;
+        private final List<ArgumentAssertion> arguments;
 
 
-        MethodAssertion(String type, String name, List<ArgumentAssertion> arguments) {
+        MethodAssertion(final String type, final String name, final List<ArgumentAssertion> arguments) {
             super(type, name);
             this.arguments = arguments;
         }
 
-        MethodAssertion(String type, String name) {
+        MethodAssertion(final String type, final String name) {
             this(type, name, Collections.<ArgumentAssertion>emptyList());
         }
 
@@ -763,8 +762,9 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
             for (ArgumentAssertion argument : arguments) {
                 sb.append(argument.type).append(' ');
                 sb.append(argument.name);
-                if(++i != arguments.size())
+                if(++i != arguments.size()) {
                     sb.append(',');
+                }
             }
             sb.append(')');
             return sb.toString();
@@ -775,7 +775,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
         protected final String type, name;
 
-        private ArgumentAssertion(String type, String name) {
+        private ArgumentAssertion(final String type, final String name) {
             this.type = type;
             this.name = name;
         }
index 8e088ba57822b00155b00aad346b93c8f897f64a..ccb72191c43376ebda39b93a35cda0770eecb69c 100644 (file)
@@ -19,7 +19,6 @@
         <dependency>\r
             <groupId>org.opendaylight.controller</groupId>\r
             <artifactId>ietf-netconf-notifications</artifactId>\r
-            <version>0.3.0-SNAPSHOT</version>\r
         </dependency>\r
         <dependency>\r
             <groupId>org.opendaylight.controller</groupId>\r
@@ -95,7 +94,6 @@
             <plugin>\r
                 <groupId>org.codehaus.mojo</groupId>\r
                 <artifactId>build-helper-maven-plugin</artifactId>\r
-                <version>1.8</version>\r
                 <executions>\r
                     <execution>\r
                         <id>add-source</id>\r
index aebde0c0432df8fb3f75085f8cc749d0b8e39bdc..a32413064e429403aeaa9a032845e3a34ee8fbde 100644 (file)
@@ -63,10 +63,7 @@ public class Topic implements DataChangeListener {
     public void notifyNode(final NodeId nodeId) {
         JoinTopicInput jti = getJoinTopicInputArgument(nodeId);
         EventSourceService ess = mdSal.getRpcService(EventSourceService.class);
-
-        if (ess == null) {
-            throw new IllegalStateException("EventSourceService is not registered.");
-        }
+        Preconditions.checkState(ess != null, "EventSourceService is not registered");
 
         ess.joinTopic(jti);
     }
index e2aa16918e8ed0354f8543f8edd74b89474e4072..1aecc89eeafa2b746f4e751f9869ed68d1229bee 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.cluster.raft;
 
+import com.google.common.base.Preconditions;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -187,9 +188,14 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
 
     @Override
     public void snapshotPreCommit(long snapshotCapturedIndex, long snapshotCapturedTerm) {
+        Preconditions.checkArgument(snapshotCapturedIndex >= snapshotIndex,
+                "snapshotCapturedIndex must be greater than or equal to snapshotIndex");
+
         snapshottedJournal = new ArrayList<>(journal.size());
 
-        snapshottedJournal.addAll(journal.subList(0, (int)(snapshotCapturedIndex - snapshotIndex)));
+        List<ReplicatedLogEntry> snapshotJournalEntries = journal.subList(0, (int) (snapshotCapturedIndex - snapshotIndex));
+
+        snapshottedJournal.addAll(snapshotJournalEntries);
         clear(0, (int) (snapshotCapturedIndex - snapshotIndex));
 
         previousSnapshotIndex = snapshotIndex;
index 78a1335d58a2ed7cacf78572425be7beb20274ca..fd49737cac45285e1fc1c89d82a157dad5179953 100644 (file)
@@ -75,7 +75,7 @@ public interface ConfigParams {
      * The interval in which the leader needs to check itself if its isolated
      * @return FiniteDuration
      */
-    FiniteDuration getIsolatedCheckInterval();
+    long getIsolatedCheckIntervalInMillis();
 
 
     /**
index 86867e1d040ee84396450ee72f6097093aecd70e..3e6742c17d37c178d30c7d570490ff993c068806 100644 (file)
@@ -42,8 +42,7 @@ public class DefaultConfigParamsImpl implements ConfigParams {
     private FiniteDuration heartBeatInterval = HEART_BEAT_INTERVAL;
     private long snapshotBatchCount = SNAPSHOT_BATCH_COUNT;
     private int journalRecoveryLogBatchSize = JOURNAL_RECOVERY_LOG_BATCH_SIZE;
-    private FiniteDuration isolatedLeaderCheckInterval =
-        new FiniteDuration(HEART_BEAT_INTERVAL.length() * 1000, HEART_BEAT_INTERVAL.unit());
+    private long isolatedLeaderCheckInterval = HEART_BEAT_INTERVAL.$times(1000).toMillis();
 
     // 12 is just an arbitrary percentage. This is the amount of the total memory that a raft actor's
     // in-memory journal can use before it needs to snapshot
@@ -68,7 +67,7 @@ public class DefaultConfigParamsImpl implements ConfigParams {
     }
 
     public void setIsolatedLeaderCheckInterval(FiniteDuration isolatedLeaderCheckInterval) {
-        this.isolatedLeaderCheckInterval = isolatedLeaderCheckInterval;
+        this.isolatedLeaderCheckInterval = isolatedLeaderCheckInterval.toMillis();
     }
 
     public void setElectionTimeoutFactor(long electionTimeoutFactor){
@@ -112,7 +111,7 @@ public class DefaultConfigParamsImpl implements ConfigParams {
     }
 
     @Override
-    public FiniteDuration getIsolatedCheckInterval() {
+    public long getIsolatedCheckIntervalInMillis() {
         return isolatedLeaderCheckInterval;
     }
 
index 935c4f0bbd7495de286196a0ce65e2502cf93f95..04b9f163f4b6ad7be0f423e485902f7b3d5ccb79 100644 (file)
@@ -100,4 +100,16 @@ public class FollowerLogInformationImpl implements FollowerLogInformation {
     public long timeSinceLastActivity() {
         return stopwatch.elapsed(TimeUnit.MILLISECONDS);
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("FollowerLogInformationImpl [id=").append(id).append(", nextIndex=").append(nextIndex)
+                .append(", matchIndex=").append(matchIndex).append(", stopwatch=")
+                .append(stopwatch.elapsed(TimeUnit.MILLISECONDS))
+                .append(", followerTimeoutMillis=").append(followerTimeoutMillis).append("]");
+        return builder.toString();
+    }
+
+
 }
index 854ceb23d047fabea219f3861c5f44c0f2afc907..285be39c0b3286c2abbdaf3c08e09c1f85c0224f 100644 (file)
@@ -22,6 +22,7 @@ import com.google.common.base.Stopwatch;
 import com.google.protobuf.ByteString;
 import java.io.Serializable;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import org.opendaylight.controller.cluster.DataPersistenceProvider;
 import org.opendaylight.controller.cluster.common.actor.AbstractUntypedPersistentActor;
 import org.opendaylight.controller.cluster.notifications.RoleChanged;
@@ -82,6 +83,9 @@ import org.slf4j.LoggerFactory;
  * </ul>
  */
 public abstract class RaftActor extends AbstractUntypedPersistentActor {
+
+    private static final long APPLY_STATE_DELAY_THRESHOLD_IN_NANOS = TimeUnit.MILLISECONDS.toNanos(50L); // 50 millis
+
     protected final Logger LOG = LoggerFactory.getLogger(getClass());
 
     /**
@@ -278,6 +282,12 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
         if (message instanceof ApplyState){
             ApplyState applyState = (ApplyState) message;
 
+            long elapsedTime = (System.nanoTime() - applyState.getStartTime());
+            if(elapsedTime >= APPLY_STATE_DELAY_THRESHOLD_IN_NANOS){
+                LOG.warn("ApplyState took more time than expected. Elapsed Time = {} ms ApplyState = {}",
+                        TimeUnit.NANOSECONDS.toMillis(elapsedTime), applyState);
+            }
+
             if(LOG.isDebugEnabled()) {
                 LOG.debug("{}: Applying state for log index {} data {}",
                     persistenceId(), applyState.getReplicatedLogEntry().getIndex(),
@@ -667,12 +677,22 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
             context.getReplicatedLog().snapshotPreCommit(captureSnapshot.getLastAppliedIndex(),
                     captureSnapshot.getLastAppliedTerm());
 
-        } else {
+            getCurrentBehavior().setReplicatedToAllIndex(captureSnapshot.getReplicatedToAllIndex());
+        } else if(captureSnapshot.getReplicatedToAllIndex() != -1){
             // clear the log based on replicatedToAllIndex
             context.getReplicatedLog().snapshotPreCommit(captureSnapshot.getReplicatedToAllIndex(),
                     captureSnapshot.getReplicatedToAllTerm());
+
+            getCurrentBehavior().setReplicatedToAllIndex(captureSnapshot.getReplicatedToAllIndex());
+        } else {
+            // The replicatedToAllIndex was not found in the log
+            // This means that replicatedToAllIndex never moved beyond -1 or that it is already in the snapshot.
+            // In this scenario we may need to save the snapshot to the akka persistence
+            // snapshot for recovery but we do not need to do the replicated log trimming.
+            context.getReplicatedLog().snapshotPreCommit(replicatedLog.getSnapshotIndex(),
+                    replicatedLog.getSnapshotTerm());
         }
-        getCurrentBehavior().setReplicatedToAllIndex(captureSnapshot.getReplicatedToAllIndex());
+
 
         LOG.info("{}: Removed in-memory snapshotted entries, adjusted snaphsotIndex:{} " +
             "and term:{}", persistenceId(), captureSnapshot.getLastAppliedIndex(),
@@ -788,7 +808,9 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
 
                             dataSizeSinceLastSnapshot = 0;
 
-                            LOG.info("{}: Initiating Snapshot Capture..", persistenceId());
+                            LOG.info("{}: Initiating Snapshot Capture, journalSize = {}, dataSizeForCheck = {}," +
+                                " dataThreshold = {}", persistenceId(), journalSize, dataSizeForCheck, dataThreshold);
+
                             long lastAppliedIndex = -1;
                             long lastAppliedTerm = -1;
 
index 0a7a6328805a82f0d26d6cb9c1124cbcf75838c6..9299e752d16ace734cf4fddfec3b22b8aea72f01 100644 (file)
@@ -9,21 +9,22 @@
 package org.opendaylight.controller.cluster.raft.base.messages;
 
 import akka.actor.ActorRef;
-import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
-
 import java.io.Serializable;
+import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 
 public class ApplyState implements Serializable {
     private static final long serialVersionUID = 1L;
     private final ActorRef clientActor;
     private final String identifier;
     private final ReplicatedLogEntry replicatedLogEntry;
+    private final long startTime;
 
     public ApplyState(ActorRef clientActor, String identifier,
         ReplicatedLogEntry replicatedLogEntry) {
         this.clientActor = clientActor;
         this.identifier = identifier;
         this.replicatedLogEntry = replicatedLogEntry;
+        this.startTime = System.nanoTime();
     }
 
     public ActorRef getClientActor() {
@@ -37,4 +38,17 @@ public class ApplyState implements Serializable {
     public ReplicatedLogEntry getReplicatedLogEntry() {
         return replicatedLogEntry;
     }
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    @Override
+    public String toString() {
+        return "ApplyState{" +
+                "identifier='" + identifier + '\'' +
+                ", replicatedLogEntry.index =" + replicatedLogEntry.getIndex() +
+                ", startTime=" + startTime +
+                '}';
+    }
 }
index b2bb127eab525e35b5f7db5995e9bd57fcbe0746..be51ba069cc5056636646566d1db00b30154073a 100644 (file)
@@ -126,6 +126,9 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
         // (heartbeat) to each server; repeat during idle periods to
         // prevent election timeouts (§5.2)
         sendAppendEntries(0, false);
+
+        // It is important to schedule this heartbeat here
+        scheduleHeartBeat(context.getConfigParams().getHeartBeatInterval());
     }
 
     /**
@@ -171,6 +174,14 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             return this;
         }
 
+        if(followerLogInformation.timeSinceLastActivity() >
+                context.getConfigParams().getElectionTimeOutInterval().toMillis()) {
+            LOG.error("{} : handleAppendEntriesReply delayed beyond election timeout, " +
+                            "appendEntriesReply : {}, timeSinceLastActivity : {}, lastApplied : {}, commitIndex : {}",
+                    logName(), appendEntriesReply, followerLogInformation.timeSinceLastActivity(),
+                    context.getLastApplied(), context.getCommitIndex());
+        }
+
         followerLogInformation.markFollowerActive();
 
         if (appendEntriesReply.isSuccess()) {
@@ -273,6 +284,8 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
         return this;
     }
 
+    protected void beforeSendHeartbeat(){}
+
     @Override
     public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
         Preconditions.checkNotNull(sender, "sender should not be null");
@@ -294,27 +307,26 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             }
         }
 
-        try {
-            if (message instanceof SendHeartBeat) {
-                sendHeartBeat();
-                return this;
+        if (message instanceof SendHeartBeat) {
+            beforeSendHeartbeat();
+            sendHeartBeat();
+            scheduleHeartBeat(context.getConfigParams().getHeartBeatInterval());
+            return this;
 
-            } else if(message instanceof SendInstallSnapshot) {
-                // received from RaftActor
-                setSnapshot(Optional.of(((SendInstallSnapshot) message).getSnapshot()));
-                sendInstallSnapshot();
+        } else if(message instanceof SendInstallSnapshot) {
+            // received from RaftActor
+            setSnapshot(Optional.of(((SendInstallSnapshot) message).getSnapshot()));
+            sendInstallSnapshot();
 
-            } else if (message instanceof Replicate) {
-                replicate((Replicate) message);
+        } else if (message instanceof Replicate) {
+            replicate((Replicate) message);
 
-            } else if (message instanceof InstallSnapshotReply){
-                handleInstallSnapshotReply((InstallSnapshotReply) message);
+        } else if (message instanceof InstallSnapshotReply){
+            handleInstallSnapshotReply((InstallSnapshotReply) message);
 
-            }
-        } finally {
-            scheduleHeartBeat(context.getConfigParams().getHeartBeatInterval());
         }
 
+
         return super.handleMessage(sender, message);
     }
 
index 1e4fcf7225daf60e0078a80ec0ca5403e0c79eab..c799441d603597ea25d530db8dc6eddc9ced68b6 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.controller.cluster.raft.behaviors;
 
 import akka.actor.ActorRef;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.protobuf.ByteString;
 import java.util.ArrayList;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftState;
@@ -330,12 +329,13 @@ public class Follower extends AbstractRaftActorBehavior {
         }
     }
 
-    @Override public void close() throws Exception {
+    @Override
+    public void close() throws Exception {
         stopElection();
     }
 
     @VisibleForTesting
-    ByteString getSnapshotChunksCollected(){
-        return snapshotTracker != null ? snapshotTracker.getCollectedChunks() : ByteString.EMPTY;
+    SnapshotTracker getSnapshotTracker(){
+        return snapshotTracker;
     }
 }
index 7a94c0c15849038f35105789856f98cb74580d51..ebcdcd40fb078ebcc16439ec2feaa87b6f62eca4 100644 (file)
@@ -8,12 +8,12 @@
 package org.opendaylight.controller.cluster.raft.behaviors;
 
 import akka.actor.ActorRef;
-import akka.actor.Cancellable;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import java.util.concurrent.TimeUnit;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
 import org.opendaylight.controller.cluster.raft.base.messages.IsolatedLeaderCheck;
-import scala.concurrent.duration.FiniteDuration;
 
 /**
  * The behavior of a RaftActor when it is in the Leader state
@@ -38,15 +38,12 @@ import scala.concurrent.duration.FiniteDuration;
  * set commitIndex = N (§5.3, Â§5.4).
  */
 public class Leader extends AbstractLeader {
-    private Cancellable installSnapshotSchedule = null;
-    private Cancellable isolatedLeaderCheckSchedule = null;
+    private static final IsolatedLeaderCheck ISOLATED_LEADER_CHECK = new IsolatedLeaderCheck();
+    private final Stopwatch isolatedLeaderCheck;
 
     public Leader(RaftActorContext context) {
         super(context);
-
-        scheduleIsolatedLeaderCheck(
-            new FiniteDuration(context.getConfigParams().getHeartBeatInterval().length() * 10,
-                context.getConfigParams().getHeartBeatInterval().unit()));
+        isolatedLeaderCheck = Stopwatch.createStarted();
     }
 
     @Override public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
@@ -54,8 +51,9 @@ public class Leader extends AbstractLeader {
 
         if (originalMessage instanceof IsolatedLeaderCheck) {
             if (isLeaderIsolated()) {
-                LOG.info("{}: At least {} followers need to be active, Switching {} from Leader to IsolatedLeader",
+                LOG.warn("{}: At least {} followers need to be active, Switching {} from Leader to IsolatedLeader",
                         context.getId(), minIsolatedLeaderPeerCount, leaderId);
+
                 return switchBehavior(new IsolatedLeader(context));
             }
         }
@@ -63,21 +61,17 @@ public class Leader extends AbstractLeader {
         return super.handleMessage(sender, originalMessage);
     }
 
-    protected void stopIsolatedLeaderCheckSchedule() {
-        if (isolatedLeaderCheckSchedule != null && !isolatedLeaderCheckSchedule.isCancelled()) {
-            isolatedLeaderCheckSchedule.cancel();
+    @Override
+    protected void beforeSendHeartbeat(){
+        if(isolatedLeaderCheck.elapsed(TimeUnit.MILLISECONDS) > context.getConfigParams().getIsolatedCheckIntervalInMillis()){
+            context.getActor().tell(ISOLATED_LEADER_CHECK, context.getActor());
+            isolatedLeaderCheck.reset().start();
         }
-    }
 
-    protected void scheduleIsolatedLeaderCheck(FiniteDuration isolatedCheckInterval) {
-        isolatedLeaderCheckSchedule = context.getActorSystem().scheduler().schedule(isolatedCheckInterval, isolatedCheckInterval,
-            context.getActor(), new IsolatedLeaderCheck(),
-            context.getActorSystem().dispatcher(), context.getActor());
     }
 
     @Override
     public void close() throws Exception {
-        stopIsolatedLeaderCheckSchedule();
         super.close();
     }
 
index 119b43ce83acad53740566e50187411308d2fc69..13636f36d7594322432377b5156fece4d6279bd6 100644 (file)
@@ -73,6 +73,7 @@ public class InstallSnapshot extends AbstractRaftRPC {
 
     public <T extends Object> Object toSerializable(){
         InstallSnapshotMessages.InstallSnapshot.Builder builder = InstallSnapshotMessages.InstallSnapshot.newBuilder()
+                .setTerm(this.getTerm())
                 .setLeaderId(this.getLeaderId())
                 .setChunkIndex(this.getChunkIndex())
                 .setData(this.getData())
index 4d33152b41ca1a575d086a5ca04be8437e25d52b..297d781251cc69854363800171599dcdc2bdc1c7 100644 (file)
@@ -53,7 +53,7 @@ public class MockRaftActorContext implements RaftActorContext {
              * Identifier of the actor whose election term information this is
              */
             private final String id = id1;
-            private long currentTerm = 0;
+            private long currentTerm = 1;
             private String votedFor = "";
 
             @Override
@@ -88,8 +88,9 @@ public class MockRaftActorContext implements RaftActorContext {
 
     public void initReplicatedLog(){
         this.replicatedLog = new SimpleReplicatedLog();
-        this.replicatedLog.append(new MockReplicatedLogEntry(1, 0, new MockPayload("1")));
-        this.replicatedLog.append(new MockReplicatedLogEntry(1, 1, new MockPayload("2")));
+        long term = getTermInformation().getCurrentTerm();
+        this.replicatedLog.append(new MockReplicatedLogEntry(term, 0, new MockPayload("1")));
+        this.replicatedLog.append(new MockReplicatedLogEntry(term, 1, new MockPayload("2")));
     }
 
     @Override public ActorRef actorOf(Props props) {
@@ -133,6 +134,16 @@ public class MockRaftActorContext implements RaftActorContext {
     }
 
     @Override
+    // FIXME : A lot of tests try to manipulate the replicated log by setting it using this method
+    // This is OK to do if the underlyingActor is not RafActor or a derived class. If not then you should not
+    // used this way to manipulate the log because the RaftActor actually has a field replicatedLog
+    // which it creates internally and sets on the RaftActorContext
+    // The only right way to manipulate the replicated log therefore is to get it from either the RaftActor
+    // or the RaftActorContext and modify the entries in there instead of trying to replace it by using this setter
+    // Simple assertion that will fail if you do so
+    // ReplicatedLog log = new ReplicatedLogImpl();
+    // raftActor.underlyingActor().getRaftActorContext().setReplicatedLog(log);
+    // assertEquals(log, raftActor.underlyingActor().getReplicatedLog())
     public void setReplicatedLog(ReplicatedLog replicatedLog) {
         this.replicatedLog = replicatedLog;
     }
@@ -255,6 +266,36 @@ public class MockRaftActorContext implements RaftActorContext {
         public String toString() {
             return value;
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((value == null) ? 0 : value.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            MockPayload other = (MockPayload) obj;
+            if (value == null) {
+                if (other.value != null) {
+                    return false;
+                }
+            } else if (!value.equals(other.value)) {
+                return false;
+            }
+            return true;
+        }
     }
 
     public static class MockReplicatedLogEntry implements ReplicatedLogEntry, Serializable {
@@ -287,6 +328,52 @@ public class MockRaftActorContext implements RaftActorContext {
         public int size() {
             return getData().size();
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((data == null) ? 0 : data.hashCode());
+            result = prime * result + (int) (index ^ (index >>> 32));
+            result = prime * result + (int) (term ^ (term >>> 32));
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            MockReplicatedLogEntry other = (MockReplicatedLogEntry) obj;
+            if (data == null) {
+                if (other.data != null) {
+                    return false;
+                }
+            } else if (!data.equals(other.data)) {
+                return false;
+            }
+            if (index != other.index) {
+                return false;
+            }
+            if (term != other.term) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("MockReplicatedLogEntry [term=").append(term).append(", index=").append(index)
+                    .append(", data=").append(data).append("]");
+            return builder.toString();
+        }
     }
 
     public static class MockReplicatedLogBuilder {
index 1cd8550be75677810a07bd79db13ebf272a4d250..56bfc21f23c2047a19d5a49c49861ae1bf6eca5e 100644 (file)
@@ -552,7 +552,6 @@ public class RaftActorTest extends AbstractActorTest {
                 assertNotEquals("voted for", "foobar", mockRaftActor.getRaftActorContext().getTermInformation().getVotedFor());
 
                 mockRaftActor.onReceiveRecover(mock(RecoveryCompleted.class));
-
             }};
     }
 
@@ -576,12 +575,12 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 mockRaftActor.getRaftActorContext().getTermInformation().updateAndPersist(10, "foobar");
 
                 assertEquals("Persist called", true, persistLatch.await(5, TimeUnit.SECONDS));
-
             }
-
         };
     }
 
@@ -602,14 +601,14 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 MockRaftActorContext.MockReplicatedLogEntry logEntry = new MockRaftActorContext.MockReplicatedLogEntry(10, 10, mock(Payload.class));
 
                 mockRaftActor.getRaftActorContext().getReplicatedLog().appendAndPersist(logEntry);
 
                 verify(dataPersistenceProvider).persist(eq(logEntry), any(Procedure.class));
-
             }
-
         };
     }
 
@@ -630,14 +629,14 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 mockRaftActor.getReplicatedLog().appendAndPersist(new MockRaftActorContext.MockReplicatedLogEntry(1, 0, mock(Payload.class)));
 
                 mockRaftActor.getRaftActorContext().getReplicatedLog().removeFromAndPersist(0);
 
                 verify(dataPersistenceProvider, times(2)).persist(anyObject(), any(Procedure.class));
-
             }
-
         };
     }
 
@@ -658,6 +657,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 mockRaftActor.onReceiveCommand(new ApplyLogEntries(10));
 
                 verify(dataPersistenceProvider, times(1)).persist(anyObject(), any(Procedure.class));
@@ -685,6 +686,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("A"),
                         new MockRaftActorContext.MockPayload("B"),
@@ -722,6 +725,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 0, mock(Payload.class)));
                 mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 1, mock(Payload.class)));
                 mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 2, mock(Payload.class)));
@@ -783,6 +788,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 ReplicatedLogEntry entry = new MockRaftActorContext.MockReplicatedLogEntry(1, 5,
                         new MockRaftActorContext.MockPayload("F"));
 
@@ -811,6 +818,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 ReplicatedLog oldReplicatedLog = mockRaftActor.getReplicatedLog();
 
                 oldReplicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, 0, mock(Payload.class)));
@@ -864,6 +873,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
+                mockRaftActor.waitForInitializeBehaviorComplete();
+
                 ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("A"),
                         new MockRaftActorContext.MockPayload("B"),
@@ -892,33 +903,44 @@ public class RaftActorTest extends AbstractActorTest {
     public void testRaftRoleChangeNotifier() throws Exception {
         new JavaTestKit(getSystem()) {{
             ActorRef notifierActor = factory.createActor(Props.create(MessageCollectorActor.class));
+            MessageCollectorActor.waitUntilReady(notifierActor);
+
             DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
+            long heartBeatInterval = 100;
+            config.setHeartBeatInterval(FiniteDuration.create(heartBeatInterval, TimeUnit.MILLISECONDS));
+            config.setElectionTimeoutFactor(1);
+
             String persistenceId = factory.generateActorId("notifier-");
 
             factory.createTestActor(MockRaftActor.props(persistenceId,
                     Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), notifierActor), persistenceId);
 
-            // sleeping for a minimum of 2 seconds, if it spans more its fine.
-            Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
+            List<RoleChanged> matches =  null;
+            for(int i = 0; i < 5000 / heartBeatInterval; i++) {
+                matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
+                assertNotNull(matches);
+                if(matches.size() == 3) {
+                    break;
+                }
+                Uninterruptibles.sleepUninterruptibly(heartBeatInterval, TimeUnit.MILLISECONDS);
+            }
 
-            List<Object> matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
-            assertNotNull(matches);
             assertEquals(3, matches.size());
 
             // check if the notifier got a role change from null to Follower
-            RoleChanged raftRoleChanged = (RoleChanged) matches.get(0);
+            RoleChanged raftRoleChanged = matches.get(0);
             assertEquals(persistenceId, raftRoleChanged.getMemberId());
             assertNull(raftRoleChanged.getOldRole());
             assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
 
             // check if the notifier got a role change from Follower to Candidate
-            raftRoleChanged = (RoleChanged) matches.get(1);
+            raftRoleChanged = matches.get(1);
             assertEquals(persistenceId, raftRoleChanged.getMemberId());
             assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
             assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
 
             // check if the notifier got a role change from Candidate to Leader
-            raftRoleChanged = (RoleChanged) matches.get(2);
+            raftRoleChanged = matches.get(2);
             assertEquals(persistenceId, raftRoleChanged.getMemberId());
             assertEquals(RaftState.Candidate.name(), raftRoleChanged.getOldRole());
             assertEquals(RaftState.Leader.name(), raftRoleChanged.getNewRole());
@@ -944,11 +966,12 @@ public class RaftActorTest extends AbstractActorTest {
                 Map<String, String> peerAddresses = new HashMap<>();
                 peerAddresses.put(follower1Id, followerActor1.path().toString());
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(),
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(
                         MockRaftActor.props(persistenceId, peerAddresses,
                                 Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
                 MockRaftActor leaderActor = mockActorRef.underlyingActor();
+
                 leaderActor.getRaftActorContext().setCommitIndex(4);
                 leaderActor.getRaftActorContext().setLastApplied(4);
                 leaderActor.getRaftActorContext().getTermInformation().update(1, persistenceId);
@@ -1034,7 +1057,7 @@ public class RaftActorTest extends AbstractActorTest {
                 Map<String, String> peerAddresses = new HashMap<>();
                 peerAddresses.put(leaderId, leaderActor1.path().toString());
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(),
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(
                         MockRaftActor.props(persistenceId, peerAddresses,
                                 Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
@@ -1204,6 +1227,128 @@ public class RaftActorTest extends AbstractActorTest {
         };
     }
 
+
+    private static class NonPersistentProvider implements DataPersistenceProvider {
+        @Override
+        public boolean isRecoveryApplicable() {
+            return false;
+        }
+
+        @Override
+        public <T> void persist(T o, Procedure<T> procedure) {
+            try {
+                procedure.apply(o);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void saveSnapshot(Object o) {
+
+        }
+
+        @Override
+        public void deleteSnapshots(SnapshotSelectionCriteria criteria) {
+
+        }
+
+        @Override
+        public void deleteMessages(long sequenceNumber) {
+
+        }
+    }
+
+    @Test
+    public void testRealSnapshotWhenReplicatedToAllIndexMinusOne() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            String persistenceId = factory.generateActorId("leader-");
+            DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
+            config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
+            config.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
+            config.setSnapshotBatchCount(5);
+
+            DataPersistenceProvider dataPersistenceProvider = new NonPersistentProvider();
+
+            Map<String, String> peerAddresses = new HashMap<>();
+
+            TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(
+                    MockRaftActor.props(persistenceId, peerAddresses,
+                            Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+
+            MockRaftActor leaderActor = mockActorRef.underlyingActor();
+            leaderActor.getRaftActorContext().setCommitIndex(3);
+            leaderActor.getRaftActorContext().setLastApplied(3);
+            leaderActor.getRaftActorContext().getTermInformation().update(1, persistenceId);
+
+            leaderActor.waitForInitializeBehaviorComplete();
+            for(int i=0;i< 4;i++) {
+                leaderActor.getReplicatedLog()
+                        .append(new MockRaftActorContext.MockReplicatedLogEntry(1, i,
+                                new MockRaftActorContext.MockPayload("A")));
+            }
+
+            Leader leader = new Leader(leaderActor.getRaftActorContext());
+            leaderActor.setCurrentBehavior(leader);
+            assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
+
+            // Persist another entry (this will cause a CaptureSnapshot to be triggered
+            leaderActor.persistData(mockActorRef, "x", new MockRaftActorContext.MockPayload("duh"));
+
+            // Now send a CaptureSnapshotReply
+            mockActorRef.tell(new CaptureSnapshotReply(fromObject("foo").toByteArray()), mockActorRef);
+
+            // Trimming log in this scenario is a no-op
+            assertEquals(-1, leaderActor.getReplicatedLog().getSnapshotIndex());
+            assertFalse(leaderActor.getRaftActorContext().isSnapshotCaptureInitiated());
+            assertEquals(-1, leader.getReplicatedToAllIndex());
+
+        }};
+    }
+
+    @Test
+    public void testRealSnapshotWhenReplicatedToAllIndexNotInReplicatedLog() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            String persistenceId = factory.generateActorId("leader-");
+            DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
+            config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
+            config.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
+            config.setSnapshotBatchCount(5);
+
+            DataPersistenceProvider dataPersistenceProvider = new NonPersistentProvider();
+
+            Map<String, String> peerAddresses = new HashMap<>();
+
+            TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(
+                    MockRaftActor.props(persistenceId, peerAddresses,
+                            Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+
+            MockRaftActor leaderActor = mockActorRef.underlyingActor();
+            leaderActor.getRaftActorContext().setCommitIndex(3);
+            leaderActor.getRaftActorContext().setLastApplied(3);
+            leaderActor.getRaftActorContext().getTermInformation().update(1, persistenceId);
+            leaderActor.getReplicatedLog().setSnapshotIndex(3);
+
+            leaderActor.waitForInitializeBehaviorComplete();
+            Leader leader = new Leader(leaderActor.getRaftActorContext());
+            leaderActor.setCurrentBehavior(leader);
+            leader.setReplicatedToAllIndex(3);
+            assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
+
+            // Persist another entry (this will cause a CaptureSnapshot to be triggered
+            leaderActor.persistData(mockActorRef, "x", new MockRaftActorContext.MockPayload("duh"));
+
+            // Now send a CaptureSnapshotReply
+            mockActorRef.tell(new CaptureSnapshotReply(fromObject("foo").toByteArray()), mockActorRef);
+
+            // Trimming log in this scenario is a no-op
+            assertEquals(3, leaderActor.getReplicatedLog().getSnapshotIndex());
+            assertFalse(leaderActor.getRaftActorContext().isSnapshotCaptureInitiated());
+            assertEquals(3, leader.getReplicatedToAllIndex());
+
+        }};
+    }
+
     private ByteString fromObject(Object snapshot) throws Exception {
         ByteArrayOutputStream b = null;
         ObjectOutputStream o = null;
index 6872c8fa4528831fda59d08ad0c3b1864054a49e..b47df13fed8c97297abf66c68bc837a03988dfb9 100644 (file)
@@ -21,6 +21,7 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
 import akka.actor.PoisonPill;
 import akka.actor.Props;
+import akka.testkit.JavaTestKit;
 import akka.testkit.TestActorRef;
 import java.util.LinkedList;
 import java.util.List;
@@ -108,10 +109,14 @@ public class TestActorFactory implements AutoCloseable {
     }
 
     @Override
-    public void close() throws Exception {
-        for(ActorRef actor : createdActors){
-            LOG.info("Killing actor {}", actor);
-            actor.tell(PoisonPill.getInstance(), null);
-        }
+    public void close() {
+        new JavaTestKit(system) {{
+            for(ActorRef actor : createdActors) {
+                watch(actor);
+                LOG.info("Killing actor {}", actor);
+                actor.tell(PoisonPill.getInstance(), ActorRef.noSender());
+                expectTerminated(duration("5 seconds"), actor);
+            }
+        }};
     }
 }
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractLeaderTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractLeaderTest.java
new file mode 100644 (file)
index 0000000..dd3ed23
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.cluster.raft.behaviors;
+
+import static org.junit.Assert.assertTrue;
+import akka.actor.ActorRef;
+import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
+import com.google.common.util.concurrent.Uninterruptibles;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
+import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
+import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat;
+import org.opendaylight.controller.cluster.raft.utils.ForwardMessageToBehaviorActor;
+import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
+import scala.concurrent.duration.FiniteDuration;
+
+public abstract class AbstractLeaderTest extends AbstractRaftActorBehaviorTest{
+
+    /**
+     * When we removed scheduling of heartbeat in the AbstractLeader constructor we ended up with a situation where
+     * if no follower responded to an initial AppendEntries heartbeats would not be sent to it. This test verifies
+     * that regardless of whether followers respond or not we schedule heartbeats.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLeaderSchedulesHeartbeatsEvenWhenNoFollowersRespondToInitialAppendEntries() throws Exception {
+        logStart("testLeaderSchedulesHeartbeatsEvenWhenNoFollowersRespondToInitialAppendEntries");
+        new JavaTestKit(getSystem()) {{
+            String leaderActorId = actorFactory.generateActorId("leader");
+            String follower1ActorId = actorFactory.generateActorId("follower");
+            String follower2ActorId = actorFactory.generateActorId("follower");
+
+            TestActorRef<ForwardMessageToBehaviorActor> leaderActor =
+                    actorFactory.createTestActor(ForwardMessageToBehaviorActor.props(), leaderActorId);
+            ActorRef follower1Actor = actorFactory.createActor(MessageCollectorActor.props(), follower1ActorId);
+            ActorRef follower2Actor = actorFactory.createActor(MessageCollectorActor.props(), follower2ActorId);
+
+            MockRaftActorContext leaderActorContext =
+                    new MockRaftActorContext(leaderActorId, getSystem(), leaderActor);
+
+            DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
+            configParams.setHeartBeatInterval(new FiniteDuration(200, TimeUnit.MILLISECONDS));
+            configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
+
+            leaderActorContext.setConfigParams(configParams);
+
+            leaderActorContext.setReplicatedLog(
+                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(1,5,1).build());
+
+            Map<String, String> peerAddresses = new HashMap<>();
+            peerAddresses.put(follower1ActorId,
+                    follower1Actor.path().toString());
+            peerAddresses.put(follower2ActorId,
+                    follower2Actor.path().toString());
+
+
+            leaderActorContext.setPeerAddresses(peerAddresses);
+
+            RaftActorBehavior leader = createBehavior(leaderActorContext);
+
+            leaderActor.underlyingActor().setBehavior(leader);
+
+            Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
+
+            List<SendHeartBeat> allMessages = MessageCollectorActor.getAllMatching(leaderActor, SendHeartBeat.class);
+
+            // Need more than 1 heartbeat to be delivered because we waited for 1 second with heartbeat interval 200ms
+            assertTrue(String.format("%s messages is less than expected", allMessages.size()),
+                    allMessages.size() > 1);
+
+        }};
+    }
+
+}
index c133c0615f0c770feea88daa1b8b82fa5cf8f661..f56755b447d347981b687cf017eded1caa059ea6 100644 (file)
@@ -1,30 +1,52 @@
 package org.opendaylight.controller.cluster.raft.behaviors;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import akka.actor.ActorRef;
 import akka.actor.Props;
-import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
+import com.google.protobuf.ByteString;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.AbstractActorTest;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
+import org.opendaylight.controller.cluster.raft.RaftState;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 import org.opendaylight.controller.cluster.raft.SerializationUtils;
+import org.opendaylight.controller.cluster.raft.TestActorFactory;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
 import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
 import org.opendaylight.controller.cluster.raft.messages.RequestVote;
 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
-import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
+import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
+import org.slf4j.LoggerFactory;
 
 public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
 
-    private final ActorRef behaviorActor = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
+    protected final TestActorFactory actorFactory = new TestActorFactory(getSystem());
+
+    private final TestActorRef<MessageCollectorActor> behaviorActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("behavior"));
+
+    RaftActorBehavior behavior;
+
+    @After
+    public void tearDown() throws Exception {
+        if(behavior != null) {
+            behavior.close();
+        }
+
+        actorFactory.close();
+    }
 
     /**
      * This test checks that when a new Raft RPC message is received with a newer
@@ -34,22 +56,19 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
      */
     @Test
     public void testHandleRaftRPCWithNewerTerm() throws Exception {
-        new JavaTestKit(getSystem()) {{
+        RaftActorContext actorContext = createActorContext();
 
-            assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(getTestActor(),
+        assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, behaviorActor,
                 createAppendEntriesWithNewerTerm());
 
-            assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(getTestActor(),
+        assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, behaviorActor,
                 createAppendEntriesReplyWithNewerTerm());
 
-            assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(getTestActor(),
+        assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, behaviorActor,
                 createRequestVoteWithNewerTerm());
 
-            assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(getTestActor(),
+        assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, behaviorActor,
                 createRequestVoteReplyWithNewerTerm());
-
-
-        }};
     }
 
 
@@ -61,144 +80,95 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
      * @throws Exception
      */
     @Test
-    public void testHandleAppendEntriesSenderTermLessThanReceiverTerm()
-        throws Exception {
-        new JavaTestKit(getSystem()) {{
-
-            MockRaftActorContext context = (MockRaftActorContext)
-                createActorContext();
+    public void testHandleAppendEntriesSenderTermLessThanReceiverTerm() throws Exception {
+            MockRaftActorContext context = createActorContext();
 
             // First set the receivers term to a high number (1000)
             context.getTermInformation().update(1000, "test");
 
-            AppendEntries appendEntries =
-                new AppendEntries(100, "leader-1", 0, 0, null, 101, -1);
+            AppendEntries appendEntries = new AppendEntries(100, "leader-1", 0, 0, null, 101, -1);
 
-            RaftActorBehavior behavior = createBehavior(context);
+            behavior = createBehavior(context);
 
             // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
+            RaftActorBehavior expected = behavior.handleMessage(behaviorActor, "unknown");
 
-            RaftActorBehavior raftBehavior =
-                behavior.handleMessage(getRef(), appendEntries);
+            RaftActorBehavior raftBehavior = behavior.handleMessage(behaviorActor, appendEntries);
 
-            assertEquals(expected, raftBehavior);
+            assertEquals("Raft state", expected.state(), raftBehavior.state());
 
             // Also expect an AppendEntriesReply to be sent where success is false
-            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
-                "AppendEntriesReply") {
-                // do not put code outside this method, will run afterwards
-                protected Boolean match(Object in) {
-                    if (in instanceof AppendEntriesReply) {
-                        AppendEntriesReply reply = (AppendEntriesReply) in;
-                        return reply.isSuccess();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get();
-
-            assertEquals(false, out);
-
-
-        }};
-    }
 
+            AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(
+                    behaviorActor, AppendEntriesReply.class);
 
-    @Test
-    public void testHandleAppendEntriesAddSameEntryToLog(){
-        new JavaTestKit(getSystem()) {
-            {
+            assertEquals("isSuccess", false, reply.isSuccess());
+    }
 
-                MockRaftActorContext context = (MockRaftActorContext)
-                    createActorContext();
 
-                // First set the receivers term to lower number
-                context.getTermInformation().update(2, "test");
+    @Test
+    public void testHandleAppendEntriesAddSameEntryToLog() throws Exception {
+        MockRaftActorContext context = createActorContext();
 
-                // Prepare the receivers log
-                MockRaftActorContext.SimpleReplicatedLog log =
-                    new MockRaftActorContext.SimpleReplicatedLog();
-                log.append(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero")));
+        context.getTermInformation().update(2, "test");
 
-                context.setReplicatedLog(log);
+        // Prepare the receivers log
+        MockRaftActorContext.MockPayload payload = new MockRaftActorContext.MockPayload("zero");
+        setLastLogEntry(context, 2, 0, payload);
 
-                List<ReplicatedLogEntry> entries = new ArrayList<>();
-                entries.add(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero")));
+        List<ReplicatedLogEntry> entries = new ArrayList<>();
+        entries.add(new MockRaftActorContext.MockReplicatedLogEntry(2, 0, payload));
 
-                AppendEntries appendEntries =
-                    new AppendEntries(2, "leader-1", -1, 1, entries, 0, -1);
+        AppendEntries appendEntries = new AppendEntries(2, "leader-1", -1, -1, entries, 2, -1);
 
-                RaftActorBehavior behavior = createBehavior(context);
+        behavior = createBehavior(context);
 
-                if (AbstractRaftActorBehaviorTest.this instanceof CandidateTest) {
-                    // Resetting the Candidates term to make sure it will match
-                    // the term sent by AppendEntries. If this was not done then
-                    // the test will fail because the Candidate will assume that
-                    // the message was sent to it from a lower term peer and will
-                    // thus respond with a failure
-                    context.getTermInformation().update(2, "test");
-                }
+        if (behavior instanceof Candidate) {
+            // Resetting the Candidates term to make sure it will match
+            // the term sent by AppendEntries. If this was not done then
+            // the test will fail because the Candidate will assume that
+            // the message was sent to it from a lower term peer and will
+            // thus respond with a failure
+            context.getTermInformation().update(2, "test");
+        }
 
-                // Send an unknown message so that the state of the RaftActor remains unchanged
-                RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
+        // Send an unknown message so that the state of the RaftActor remains unchanged
+        RaftActorBehavior expected = behavior.handleMessage(behaviorActor, "unknown");
 
-                RaftActorBehavior raftBehavior =
-                    behavior.handleMessage(getRef(), appendEntries);
+        RaftActorBehavior raftBehavior = behavior.handleMessage(behaviorActor, appendEntries);
 
-                assertEquals(expected, raftBehavior);
+        assertEquals("Raft state", expected.state(), raftBehavior.state());
 
-                assertEquals(1, log.size());
+        assertEquals("ReplicatedLog size", 1, context.getReplicatedLog().size());
 
+        handleAppendEntriesAddSameEntryToLogReply(behaviorActor);
+    }
 
-            }};
+    protected void handleAppendEntriesAddSameEntryToLogReply(TestActorRef<MessageCollectorActor> replyActor)
+            throws Exception {
+        AppendEntriesReply reply = MessageCollectorActor.getFirstMatching(replyActor, AppendEntriesReply.class);
+        Assert.assertNull("Expected no AppendEntriesReply", reply);
     }
 
     /**
      * This test verifies that when a RequestVote is received by the RaftActor
-     * with a term which is greater than the RaftActors' currentTerm and the
-     * senders' log is more upto date than the receiver that the receiver grants
-     * the vote to the sender
+     * with the senders' log is more up to date than the receiver that the receiver grants
+     * the vote to the sender.
      */
     @Test
-    public void testHandleRequestVoteWhenSenderTermGreaterThanCurrentTermAndSenderLogMoreUpToDate() {
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    RaftActorBehavior behavior = createBehavior(
-                        createActorContext(behaviorActor));
-
-                    RaftActorBehavior raftBehavior = behavior.handleMessage(getTestActor(),
-                        new RequestVote(1000, "test", 10000, 999));
-
-                    if(!(behavior instanceof Follower)){
-                        assertTrue(raftBehavior instanceof Follower);
-                    } else {
-
-                        final Boolean out =
-                            new ExpectMsg<Boolean>(duration("1 seconds"),
-                                "RequestVoteReply") {
-                                // do not put code outside this method, will run afterwards
-                                protected Boolean match(Object in) {
-                                    if (in instanceof RequestVoteReply) {
-                                        RequestVoteReply reply =
-                                            (RequestVoteReply) in;
-                                        return reply.isVoteGranted();
-                                    } else {
-                                        throw noMatch();
-                                    }
-                                }
-                            }.get();
-
-                        assertEquals(true, out);
-                    }
-                }
-            };
-        }};
+    public void testHandleRequestVoteWhenSenderLogMoreUpToDate() {
+        MockRaftActorContext context = createActorContext();
+
+        behavior = createBehavior(context);
+
+        context.getTermInformation().update(1, "test");
+
+        behavior.handleMessage(behaviorActor, new RequestVote(context.getTermInformation().getCurrentTerm(),
+                "test", 10000, 999));
+
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(behaviorActor,
+                RequestVoteReply.class);
+        assertEquals("isVoteGranted", true, reply.isVoteGranted());
     }
 
     /**
@@ -207,51 +177,24 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
      * log then the receiving RaftActor will not grant the vote to the sender
      */
     @Test
-    public void testHandleRequestVoteWhenSenderTermGreaterThanCurrentTermButSenderLogLessUptoDate() {
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    RaftActorContext actorContext =
-                        createActorContext(behaviorActor);
-
-                    MockRaftActorContext.SimpleReplicatedLog
-                        log = new MockRaftActorContext.SimpleReplicatedLog();
-                    log.append(
-                        new MockRaftActorContext.MockReplicatedLogEntry(20000,
-                            1000000, new MockRaftActorContext.MockPayload("")));
-
-                    ((MockRaftActorContext) actorContext).setReplicatedLog(log);
-
-                    RaftActorBehavior behavior = createBehavior(actorContext);
-
-                    RaftActorBehavior raftBehavior = behavior.handleMessage(getTestActor(),
-                        new RequestVote(1000, "test", 10000, 999));
-
-                    if(!(behavior instanceof Follower)){
-                        assertTrue(raftBehavior instanceof Follower);
-                    } else {
-                        final Boolean out =
-                            new ExpectMsg<Boolean>(duration("1 seconds"),
-                                "RequestVoteReply") {
-                                // do not put code outside this method, will run afterwards
-                                protected Boolean match(Object in) {
-                                    if (in instanceof RequestVoteReply) {
-                                        RequestVoteReply reply =
-                                            (RequestVoteReply) in;
-                                        return reply.isVoteGranted();
-                                    } else {
-                                        throw noMatch();
-                                    }
-                                }
-                            }.get();
-
-                        assertEquals(false, out);
-                    }
-                }
-            };
-        }};
+    public void testHandleRequestVoteWhenSenderLogLessUptoDate() {
+        MockRaftActorContext context = createActorContext();
+
+        behavior = createBehavior(context);
+
+        context.getTermInformation().update(1, "test");
+
+        int index = 2000;
+        setLastLogEntry(context, context.getTermInformation().getCurrentTerm(), index,
+                new MockRaftActorContext.MockPayload(""));
+
+        behavior.handleMessage(behaviorActor, new RequestVote(
+                context.getTermInformation().getCurrentTerm(), "test",
+                index - 1, context.getTermInformation().getCurrentTerm()));
+
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(behaviorActor,
+                RequestVoteReply.class);
+        assertEquals("isVoteGranted", false, reply.isVoteGranted());
     }
 
 
@@ -263,40 +206,17 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
      */
     @Test
     public void testHandleRequestVoteWhenSenderTermLessThanCurrentTerm() {
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    RaftActorContext context =
-                        createActorContext(behaviorActor);
-
-                    context.getTermInformation().update(1000, null);
-
-                    RaftActorBehavior follower = createBehavior(context);
-
-                    follower.handleMessage(getTestActor(),
-                        new RequestVote(999, "test", 10000, 999));
-
-                    final Boolean out =
-                        new ExpectMsg<Boolean>(duration("1 seconds"),
-                            "RequestVoteReply") {
-                            // do not put code outside this method, will run afterwards
-                            protected Boolean match(Object in) {
-                                if (in instanceof RequestVoteReply) {
-                                    RequestVoteReply reply =
-                                        (RequestVoteReply) in;
-                                    return reply.isVoteGranted();
-                                } else {
-                                    throw noMatch();
-                                }
-                            }
-                        }.get();
-
-                    assertEquals(false, out);
-                }
-            };
-        }};
+        RaftActorContext context = createActorContext();
+
+        context.getTermInformation().update(1000, null);
+
+        behavior = createBehavior(context);
+
+        behavior.handleMessage(behaviorActor, new RequestVote(999, "test", 10000, 999));
+
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(behaviorActor,
+                RequestVoteReply.class);
+        assertEquals("isVoteGranted", false, reply.isVoteGranted());
     }
 
     @Test
@@ -346,18 +266,21 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
     }
 
 
-    protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(
-        ActorRef actorRef, RaftRPC rpc) {
+    protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(RaftActorContext actorContext,
+            ActorRef actorRef, RaftRPC rpc) throws Exception {
 
-        RaftActorContext actorContext = createActorContext();
         Payload p = new MockRaftActorContext.MockPayload("");
-        setLastLogEntry(
-            (MockRaftActorContext) actorContext, 0, 0, p);
+        setLastLogEntry((MockRaftActorContext) actorContext, 1, 0, p);
+        actorContext.getTermInformation().update(1, "test");
+
+        RaftActorBehavior origBehavior = createBehavior(actorContext);
+        RaftActorBehavior raftBehavior = origBehavior.handleMessage(actorRef, rpc);
 
-        RaftActorBehavior raftBehavior = createBehavior(actorContext)
-            .handleMessage(actorRef, rpc);
+        assertEquals("New raft state", RaftState.Follower, raftBehavior.state());
+        assertEquals("New election term", rpc.getTerm(), actorContext.getTermInformation().getCurrentTerm());
 
-        assertTrue(raftBehavior instanceof Follower);
+        origBehavior.close();
+        raftBehavior.close();
     }
 
     protected MockRaftActorContext.SimpleReplicatedLog setLastLogEntry(
@@ -366,10 +289,9 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
             new MockRaftActorContext.MockReplicatedLogEntry(term, index, data));
     }
 
-    protected MockRaftActorContext.SimpleReplicatedLog setLastLogEntry(
-        MockRaftActorContext actorContext, ReplicatedLogEntry logEntry) {
-        MockRaftActorContext.SimpleReplicatedLog
-            log = new MockRaftActorContext.SimpleReplicatedLog();
+    protected MockRaftActorContext.SimpleReplicatedLog setLastLogEntry(MockRaftActorContext actorContext,
+            ReplicatedLogEntry logEntry) {
+        MockRaftActorContext.SimpleReplicatedLog log = new MockRaftActorContext.SimpleReplicatedLog();
         log.append(logEntry);
         actorContext.setReplicatedLog(log);
 
@@ -383,11 +305,11 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
         return createBehavior(createActorContext());
     }
 
-    protected RaftActorContext createActorContext() {
+    protected MockRaftActorContext createActorContext() {
         return new MockRaftActorContext();
     }
 
-    protected RaftActorContext createActorContext(ActorRef actor) {
+    protected MockRaftActorContext createActorContext(ActorRef actor) {
         return new MockRaftActorContext("test", getSystem(), actor);
     }
 
@@ -410,4 +332,18 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
     protected Object fromSerializableMessage(Object serializable){
         return SerializationUtils.fromSerializable(serializable);
     }
+
+    protected ByteString toByteString(Map<String, String> state) {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try(ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+            oos.writeObject(state);
+            return ByteString.copyFrom(bos.toByteArray());
+        } catch (IOException e) {
+            throw new AssertionError("IOException occurred converting Map to Bytestring", e);
+        }
+    }
+
+    protected void logStart(String name) {
+        LoggerFactory.getLogger(LeaderTest.class).info("Starting " + name);
+    }
 }
index 0dc68c2461c2235b22e663b39ad51220e96c80b5..60f45523cf204d5d246fb14ac01eddc4dcc760ba 100644 (file)
@@ -1,68 +1,48 @@
 package org.opendaylight.controller.cluster.raft.behaviors;
 
+import static org.junit.Assert.assertEquals;
 import akka.actor.ActorRef;
 import akka.actor.Props;
-import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import org.junit.Assert;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
+import org.opendaylight.controller.cluster.raft.RaftState;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
+import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
 import org.opendaylight.controller.cluster.raft.messages.RequestVote;
 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
-import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
-
-import static org.junit.Assert.assertEquals;
+import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
 
 public class CandidateTest extends AbstractRaftActorBehaviorTest {
 
-    private final ActorRef candidateActor = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
-
-    private final ActorRef peerActor1 = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
+    private final TestActorRef<MessageCollectorActor> candidateActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("candidate"));
 
-    private final ActorRef peerActor2 = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
+    private TestActorRef<MessageCollectorActor>[] peerActors;
 
-    private final ActorRef peerActor3 = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
-
-    private final ActorRef peerActor4 = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
-
-    private final Map<String, String> onePeer = new HashMap<>();
-    private final Map<String, String> twoPeers = new HashMap<>();
-    private final Map<String, String> fourPeers = new HashMap<>();
+    private RaftActorBehavior candidate;
 
     @Before
     public void setUp(){
-        onePeer.put(peerActor1.path().toString(),
-            peerActor1.path().toString());
-
-        twoPeers.put(peerActor1.path().toString(),
-            peerActor1.path().toString());
-        twoPeers.put(peerActor2.path().toString(),
-            peerActor2.path().toString());
-
-        fourPeers.put(peerActor1.path().toString(),
-            peerActor1.path().toString());
-        fourPeers.put(peerActor2.path().toString(),
-            peerActor2.path().toString());
-        fourPeers.put(peerActor3.path().toString(),
-            peerActor3.path().toString());
-        fourPeers.put(peerActor4.path().toString(),
-            peerActor3.path().toString());
+    }
 
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        if(candidate != null) {
+            candidate.close();
+        }
 
+        super.tearDown();
     }
 
     @Test
@@ -70,230 +50,167 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest {
         RaftActorContext raftActorContext = createActorContext();
         long expectedTerm = raftActorContext.getTermInformation().getCurrentTerm();
 
-        new Candidate(raftActorContext);
+        candidate = new Candidate(raftActorContext);
 
-        assertEquals(expectedTerm+1, raftActorContext.getTermInformation().getCurrentTerm());
-        assertEquals(raftActorContext.getId(), raftActorContext.getTermInformation().getVotedFor());
+        assertEquals("getCurrentTerm", expectedTerm+1, raftActorContext.getTermInformation().getCurrentTerm());
+        assertEquals("getVotedFor", raftActorContext.getId(), raftActorContext.getTermInformation().getVotedFor());
     }
 
     @Test
     public void testThatAnElectionTimeoutIsTriggered(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6)) {
-                protected void run() {
-
-                    Candidate candidate = new Candidate(createActorContext(getTestActor()));
-
-                    final Boolean out = new ExpectMsg<Boolean>(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6), "ElectionTimeout") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof ElectionTimeout) {
-                                 return true;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
-
-                    assertEquals(true, out);
-                }
-            };
-        }};
+         MockRaftActorContext actorContext = createActorContext();
+         candidate = new Candidate(actorContext);
+
+         MessageCollectorActor.expectFirstMatching(candidateActor, ElectionTimeout.class,
+                 actorContext.getConfigParams().getElectionTimeOutInterval().$times(6).toMillis());
     }
 
     @Test
     public void testHandleElectionTimeoutWhenThereAreZeroPeers(){
         RaftActorContext raftActorContext = createActorContext();
-        Candidate candidate =
-            new Candidate(raftActorContext);
+        candidate = new Candidate(raftActorContext);
 
-        RaftActorBehavior raftBehavior =
+        RaftActorBehavior newBehavior =
             candidate.handleMessage(candidateActor, new ElectionTimeout());
 
-        Assert.assertTrue(raftBehavior instanceof Leader);
+        assertEquals("Behavior", RaftState.Leader, newBehavior.state());
     }
 
     @Test
-    public void testHandleElectionTimeoutWhenThereAreTwoNodesInCluster(){
-        MockRaftActorContext raftActorContext =
-            (MockRaftActorContext) createActorContext();
-        raftActorContext.setPeerAddresses(onePeer);
-        Candidate candidate =
-            new Candidate(raftActorContext);
-
-        RaftActorBehavior raftBehavior =
-            candidate.handleMessage(candidateActor, new ElectionTimeout());
+    public void testHandleElectionTimeoutWhenThereAreTwoNodeCluster(){
+        MockRaftActorContext raftActorContext = createActorContext();
+        raftActorContext.setPeerAddresses(setupPeers(1));
+        candidate = new Candidate(raftActorContext);
+
+        candidate = candidate.handleMessage(candidateActor, new ElectionTimeout());
 
-        Assert.assertTrue(raftBehavior instanceof Candidate);
+        assertEquals("Behavior", RaftState.Candidate, candidate.state());
     }
 
     @Test
-    public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodesInCluster(){
-        MockRaftActorContext raftActorContext =
-            (MockRaftActorContext) createActorContext();
-        raftActorContext.setPeerAddresses(twoPeers);
-        Candidate candidate =
-            new Candidate(raftActorContext);
-
-        RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
+    public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodeCluster(){
+        MockRaftActorContext raftActorContext = createActorContext();
+        raftActorContext.setPeerAddresses(setupPeers(2));
+        candidate = new Candidate(raftActorContext);
 
-        Assert.assertTrue(behaviorOnFirstVote instanceof Leader);
+        candidate = candidate.handleMessage(peerActors[0], new RequestVoteReply(1, true));
 
+        assertEquals("Behavior", RaftState.Leader, candidate.state());
     }
 
     @Test
-    public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodesInCluster(){
-        MockRaftActorContext raftActorContext =
-            (MockRaftActorContext) createActorContext();
-        raftActorContext.setPeerAddresses(fourPeers);
-        Candidate candidate =
-            new Candidate(raftActorContext);
+    public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodeCluster(){
+        MockRaftActorContext raftActorContext = createActorContext();
+        raftActorContext.setPeerAddresses(setupPeers(4));
+        candidate = new Candidate(raftActorContext);
 
-        RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
+        // First peers denies the vote.
+        candidate = candidate.handleMessage(peerActors[0], new RequestVoteReply(1, false));
 
-        RaftActorBehavior behaviorOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true));
+        assertEquals("Behavior", RaftState.Candidate, candidate.state());
 
-        Assert.assertTrue(behaviorOnFirstVote instanceof Candidate);
-        Assert.assertTrue(behaviorOnSecondVote instanceof Leader);
+        candidate = candidate.handleMessage(peerActors[1], new RequestVoteReply(1, true));
 
-    }
+        assertEquals("Behavior", RaftState.Candidate, candidate.state());
 
-    @Test
-    public void testResponseToAppendEntriesWithLowerTerm(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    Candidate candidate = new Candidate(createActorContext(getTestActor()));
-
-                    candidate.handleMessage(getTestActor(), new AppendEntries(0, "test", 0,0,Collections.<ReplicatedLogEntry>emptyList(), 0, -1));
-
-                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "AppendEntriesResponse") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof AppendEntriesReply) {
-                                AppendEntriesReply reply = (AppendEntriesReply) in;
-                                return reply.isSuccess();
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
-
-                    assertEquals(false, out);
-                }
-            };
-        }};
+        candidate = candidate.handleMessage(peerActors[2], new RequestVoteReply(1, true));
+
+        assertEquals("Behavior", RaftState.Leader, candidate.state());
     }
 
     @Test
-    public void testResponseToRequestVoteWithLowerTerm(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    Candidate candidate = new Candidate(createActorContext(getTestActor()));
-
-                    candidate.handleMessage(getTestActor(), new RequestVote(0, "test", 0, 0));
-
-                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "AppendEntriesResponse") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof RequestVoteReply) {
-                                RequestVoteReply reply = (RequestVoteReply) in;
-                                return reply.isVoteGranted();
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
-
-                    assertEquals(false, out);
-                }
-            };
-        }};
+    public void testResponseToHandleAppendEntriesWithLowerTerm() {
+        candidate = new Candidate(createActorContext());
+
+        setupPeers(1);
+        candidate.handleMessage(peerActors[0], new AppendEntries(1, "test", 0, 0,
+                Collections.<ReplicatedLogEntry>emptyList(), 0, -1));
+
+        AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(
+                peerActors[0], AppendEntriesReply.class);
+        assertEquals("isSuccess", false, reply.isSuccess());
+        assertEquals("getTerm", 2, reply.getTerm());
     }
 
     @Test
-    public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNull(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    RaftActorContext context = createActorContext(getTestActor());
-
-                    context.getTermInformation().update(1000, null);
-
-                    // Once a candidate is created it will immediately increment the current term so after
-                    // construction the currentTerm should be 1001
-                    RaftActorBehavior follower = createBehavior(context);
-
-                    follower.handleMessage(getTestActor(), new RequestVote(1001, "test", 10000, 999));
-
-                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof RequestVoteReply) {
-                                RequestVoteReply reply = (RequestVoteReply) in;
-                                return reply.isVoteGranted();
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
-
-                    assertEquals(true, out);
-                }
-            };
-        }};
+    public void testResponseToRequestVoteWithLowerTerm() {
+        candidate = new Candidate(createActorContext());
+
+        setupPeers(1);
+        candidate.handleMessage(peerActors[0], new RequestVote(1, "test", 0, 0));
+
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(
+                peerActors[0], RequestVoteReply.class);
+        assertEquals("isVoteGranted", false, reply.isVoteGranted());
+        assertEquals("getTerm", 2, reply.getTerm());
     }
 
     @Test
-    public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNotTheSameAsCandidateId(){
-        new JavaTestKit(getSystem()) {{
+    public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForMatches() {
+        MockRaftActorContext context = createActorContext();
+        context.getTermInformation().update(1000, null);
 
-            new Within(duration("1 seconds")) {
-                protected void run() {
+        // Once a candidate is created it will immediately increment the current term so after
+        // construction the currentTerm should be 1001
+        candidate = new Candidate(context);
 
-                    RaftActorContext context = createActorContext(getTestActor());
+        setupPeers(1);
+        candidate.handleMessage(peerActors[0], new RequestVote(1001, context.getId(), 10000, 999));
 
-                    context.getTermInformation().update(1000, "test");
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(
+                peerActors[0], RequestVoteReply.class);
+        assertEquals("isVoteGranted", true, reply.isVoteGranted());
+        assertEquals("getTerm", 1001, reply.getTerm());
+    }
+
+    @Test
+    public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForDoesNotMatch() {
+        MockRaftActorContext context = createActorContext();
+        context.getTermInformation().update(1000, null);
 
-                    RaftActorBehavior follower = createBehavior(context);
+        // Once a candidate is created it will immediately increment the current term so after
+        // construction the currentTerm should be 1001
+        candidate = new Candidate(context);
 
-                    follower.handleMessage(getTestActor(), new RequestVote(1001, "candidate", 10000, 999));
+        setupPeers(1);
 
-                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof RequestVoteReply) {
-                                RequestVoteReply reply = (RequestVoteReply) in;
-                                return reply.isVoteGranted();
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
+        // RequestVote candidate ID ("candidate2") does not match this candidate's votedFor
+        // (it votes for itself)
+        candidate.handleMessage(peerActors[0], new RequestVote(1001, "candidate2", 10000, 999));
 
-                    assertEquals(false, out);
-                }
-            };
-        }};
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(
+                peerActors[0], RequestVoteReply.class);
+        assertEquals("isVoteGranted", false, reply.isVoteGranted());
+        assertEquals("getTerm", 1001, reply.getTerm());
     }
 
 
 
-    @Override protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
+    @Override
+    protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
         return new Candidate(actorContext);
     }
 
-    @Override protected RaftActorContext createActorContext() {
-        return new MockRaftActorContext("test", getSystem(), candidateActor);
+    @Override protected MockRaftActorContext createActorContext() {
+        return new MockRaftActorContext("candidate", getSystem(), candidateActor);
     }
 
+    private Map<String, String> setupPeers(int count) {
+        Map<String, String> peerMap = new HashMap<>();
+        peerActors = new TestActorRef[count];
+        for(int i = 0; i < count; i++) {
+            peerActors[i] = actorFactory.createTestActor(Props.create(MessageCollectorActor.class),
+                    actorFactory.generateActorId("peer"));
+            peerMap.put("peer" + (i+1), peerActors[i].path().toString());
+        }
 
+        return peerMap;
+    }
+
+    @Override
+    protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(RaftActorContext actorContext,
+            ActorRef actorRef, RaftRPC rpc) throws Exception {
+        super.assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, actorRef, rpc);
+        assertEquals("New votedFor", null, actorContext.getTermInformation().getVotedFor());
+    }
 }
index 719a8256a0757f406777a8d03b52fab879009c74..4e8e7fe11bad4fdeb085ffc1ac60450cbbfeda11 100644 (file)
 package org.opendaylight.controller.cluster.raft.behaviors;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import akka.actor.ActorRef;
 import akka.actor.Props;
-import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
 import com.google.protobuf.ByteString;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Test;
-import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
+import org.opendaylight.controller.cluster.raft.Snapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
 import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot;
 import org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply;
+import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
 import org.opendaylight.controller.cluster.raft.messages.RequestVote;
 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
-import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
 
 public class FollowerTest extends AbstractRaftActorBehaviorTest {
 
-    private final ActorRef followerActor = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
+    private final TestActorRef<MessageCollectorActor> followerActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("follower"));
 
+    private final TestActorRef<MessageCollectorActor> leaderActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("leader"));
 
-    @Override protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
+    private RaftActorBehavior follower;
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        if(follower != null) {
+            follower.close();
+        }
+
+        super.tearDown();
+    }
+
+    @Override
+    protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
         return new Follower(actorContext);
     }
 
-    @Override protected  RaftActorContext createActorContext() {
+    @Override
+    protected  MockRaftActorContext createActorContext() {
         return createActorContext(followerActor);
     }
 
-    protected  RaftActorContext createActorContext(ActorRef actorRef){
-        return new MockRaftActorContext("test", getSystem(), actorRef);
+    @Override
+    protected  MockRaftActorContext createActorContext(ActorRef actorRef){
+        return new MockRaftActorContext("follower", getSystem(), actorRef);
     }
 
     @Test
     public void testThatAnElectionTimeoutIsTriggered(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6)) {
-                protected void run() {
-
-                    Follower follower = new Follower(createActorContext(getTestActor()));
-
-                    final Boolean out = new ExpectMsg<Boolean>(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6), "ElectionTimeout") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof ElectionTimeout) {
-                                return true;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
-
-                    assertEquals(true, out);
-                }
-            };
-        }};
+        MockRaftActorContext actorContext = createActorContext();
+        follower = new Follower(actorContext);
+
+        MessageCollectorActor.expectFirstMatching(followerActor, ElectionTimeout.class,
+                actorContext.getConfigParams().getElectionTimeOutInterval().$times(6).toMillis());
     }
 
     @Test
     public void testHandleElectionTimeout(){
-        RaftActorContext raftActorContext = createActorContext();
-        Follower follower =
-            new Follower(raftActorContext);
+        logStart("testHandleElectionTimeout");
 
-        RaftActorBehavior raftBehavior =
-            follower.handleMessage(followerActor, new ElectionTimeout());
+        follower = new Follower(createActorContext());
+
+        RaftActorBehavior raftBehavior = follower.handleMessage(followerActor, new ElectionTimeout());
 
         assertTrue(raftBehavior instanceof Candidate);
     }
 
     @Test
     public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNull(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    RaftActorContext context = createActorContext(getTestActor());
+        logStart("testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNull");
 
-                    context.getTermInformation().update(1000, null);
+        RaftActorContext context = createActorContext();
+        long term = 1000;
+        context.getTermInformation().update(term, null);
 
-                    RaftActorBehavior follower = createBehavior(context);
+        follower = createBehavior(context);
 
-                    follower.handleMessage(getTestActor(), new RequestVote(1000, "test", 10000, 999));
+        follower.handleMessage(leaderActor, new RequestVote(term, "test", 10000, 999));
 
-                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof RequestVoteReply) {
-                                RequestVoteReply reply = (RequestVoteReply) in;
-                                return reply.isVoteGranted();
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(leaderActor, RequestVoteReply.class);
 
-                    assertEquals(true, out);
-                }
-            };
-        }};
+        assertEquals("isVoteGranted", true, reply.isVoteGranted());
+        assertEquals("getTerm", term, reply.getTerm());
     }
 
     @Test
     public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNotTheSameAsCandidateId(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                protected void run() {
-
-                    RaftActorContext context = createActorContext(getTestActor());
+        logStart("testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNotTheSameAsCandidateId");
 
-                    context.getTermInformation().update(1000, "test");
+        RaftActorContext context = createActorContext();
+        long term = 1000;
+        context.getTermInformation().update(term, "test");
 
-                    RaftActorBehavior follower = createBehavior(context);
+        follower = createBehavior(context);
 
-                    follower.handleMessage(getTestActor(), new RequestVote(1000, "candidate", 10000, 999));
+        follower.handleMessage(leaderActor, new RequestVote(term, "candidate", 10000, 999));
 
-                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
-                        // do not put code outside this method, will run afterwards
-                        protected Boolean match(Object in) {
-                            if (in instanceof RequestVoteReply) {
-                                RequestVoteReply reply = (RequestVoteReply) in;
-                                return reply.isVoteGranted();
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get();
+        RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(leaderActor, RequestVoteReply.class);
 
-                    assertEquals(false, out);
-                }
-            };
-        }};
+        assertEquals("isVoteGranted", false, reply.isVoteGranted());
     }
 
     /**
@@ -163,32 +128,25 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
      */
     @Test
     public void testHandleAppendEntriesWithNewerCommitIndex() throws Exception {
-        new JavaTestKit(getSystem()) {{
+        logStart("testHandleAppendEntriesWithNewerCommitIndex");
 
-            RaftActorContext context =
-                createActorContext();
+        MockRaftActorContext context = createActorContext();
 
-            context.setLastApplied(100);
-            setLastLogEntry((MockRaftActorContext) context, 1, 100,
+        context.setLastApplied(100);
+        setLastLogEntry(context, 1, 100,
                 new MockRaftActorContext.MockPayload(""));
-            ((MockRaftActorContext) context).getReplicatedLog().setSnapshotIndex(99);
+        context.getReplicatedLog().setSnapshotIndex(99);
 
-            List<ReplicatedLogEntry> entries =
-                Arrays.asList(
-                        (ReplicatedLogEntry) new MockRaftActorContext.MockReplicatedLogEntry(2, 101,
-                                new MockRaftActorContext.MockPayload("foo"))
-                );
+        List<ReplicatedLogEntry> entries = Arrays.<ReplicatedLogEntry>asList(
+                newReplicatedLogEntry(2, 101, "foo"));
 
-            // The new commitIndex is 101
-            AppendEntries appendEntries =
-                new AppendEntries(2, "leader-1", 100, 1, entries, 101, 100);
+        // The new commitIndex is 101
+        AppendEntries appendEntries = new AppendEntries(2, "leader-1", 100, 1, entries, 101, 100);
 
-            RaftActorBehavior raftBehavior =
-                createBehavior(context).handleMessage(getRef(), appendEntries);
+        follower = createBehavior(context);
+        follower.handleMessage(leaderActor, appendEntries);
 
-            assertEquals(101L, context.getLastApplied());
-
-        }};
+        assertEquals("getLastApplied", 101L, context.getLastApplied());
     }
 
     /**
@@ -199,58 +157,30 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
      * @throws Exception
      */
     @Test
-    public void testHandleAppendEntriesSenderPrevLogTermNotSameAsReceiverPrevLogTerm()
-        throws Exception {
-        new JavaTestKit(getSystem()) {{
-
-            MockRaftActorContext context = (MockRaftActorContext)
-                createActorContext();
-
-            // First set the receivers term to lower number
-            context.getTermInformation().update(95, "test");
-
-            // Set the last log entry term for the receiver to be greater than
-            // what we will be sending as the prevLogTerm in AppendEntries
-            MockRaftActorContext.SimpleReplicatedLog mockReplicatedLog =
-                setLastLogEntry(context, 20, 0, new MockRaftActorContext.MockPayload(""));
-
-            // AppendEntries is now sent with a bigger term
-            // this will set the receivers term to be the same as the sender's term
-            AppendEntries appendEntries =
-                new AppendEntries(100, "leader-1", 0, 0, null, 101, -1);
+    public void testHandleAppendEntriesSenderPrevLogTermNotSameAsReceiverPrevLogTerm() {
+        logStart("testHandleAppendEntriesSenderPrevLogTermNotSameAsReceiverPrevLogTerm");
 
-            RaftActorBehavior behavior = createBehavior(context);
+        MockRaftActorContext context = createActorContext();
 
-            // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
+        // First set the receivers term to lower number
+        context.getTermInformation().update(95, "test");
 
-            RaftActorBehavior raftBehavior =
-                behavior.handleMessage(getRef(), appendEntries);
+        // AppendEntries is now sent with a bigger term
+        // this will set the receivers term to be the same as the sender's term
+        AppendEntries appendEntries = new AppendEntries(100, "leader", 0, 0, null, 101, -1);
 
-            assertEquals(expected, raftBehavior);
+        follower = createBehavior(context);
 
-            // Also expect an AppendEntriesReply to be sent where success is false
-            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
-                "AppendEntriesReply") {
-                // do not put code outside this method, will run afterwards
-                protected Boolean match(Object in) {
-                    if (in instanceof AppendEntriesReply) {
-                        AppendEntriesReply reply = (AppendEntriesReply) in;
-                        return reply.isSuccess();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get();
+        RaftActorBehavior newBehavior = follower.handleMessage(leaderActor, appendEntries);
 
-            assertEquals(false, out);
+        Assert.assertSame(follower, newBehavior);
 
+        AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(leaderActor,
+                AppendEntriesReply.class);
 
-        }};
+        assertEquals("isSuccess", false, reply.isSuccess());
     }
 
-
-
     /**
      * This test verifies that when a new AppendEntries message is received with
      * new entries and the logs of the sender and receiver match that the new
@@ -260,278 +190,201 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
      * @throws Exception
      */
     @Test
-    public void testHandleAppendEntriesAddNewEntries() throws Exception {
-        new JavaTestKit(getSystem()) {{
-
-            MockRaftActorContext context = (MockRaftActorContext)
-                createActorContext();
-
-            // First set the receivers term to lower number
-            context.getTermInformation().update(1, "test");
-
-            // Prepare the receivers log
-            MockRaftActorContext.SimpleReplicatedLog log =
-                new MockRaftActorContext.SimpleReplicatedLog();
-            log.append(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero")));
-            log.append(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("one")));
-            log.append(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 2, new MockRaftActorContext.MockPayload("two")));
-
-            context.setReplicatedLog(log);
-
-            // Prepare the entries to be sent with AppendEntries
-            List<ReplicatedLogEntry> entries = new ArrayList<>();
-            entries.add(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 3, new MockRaftActorContext.MockPayload("three")));
-            entries.add(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 4, new MockRaftActorContext.MockPayload("four")));
-
-            // Send appendEntries with the same term as was set on the receiver
-            // before the new behavior was created (1 in this case)
-            // This will not work for a Candidate because as soon as a Candidate
-            // is created it increments the term
-            AppendEntries appendEntries =
-                new AppendEntries(1, "leader-1", 2, 1, entries, 4, -1);
-
-            RaftActorBehavior behavior = createBehavior(context);
-
-            // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
-
-            RaftActorBehavior raftBehavior =
-                behavior.handleMessage(getRef(), appendEntries);
-
-            assertEquals(expected, raftBehavior);
-            assertEquals(5, log.last().getIndex() + 1);
-            assertNotNull(log.get(3));
-            assertNotNull(log.get(4));
-
-            // Also expect an AppendEntriesReply to be sent where success is false
-            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
-                "AppendEntriesReply") {
-                // do not put code outside this method, will run afterwards
-                protected Boolean match(Object in) {
-                    if (in instanceof AppendEntriesReply) {
-                        AppendEntriesReply reply = (AppendEntriesReply) in;
-                        return reply.isSuccess();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get();
-
-            assertEquals(true, out);
-
-
-        }};
-    }
+    public void testHandleAppendEntriesAddNewEntries() {
+        logStart("testHandleAppendEntriesAddNewEntries");
+
+        MockRaftActorContext context = createActorContext();
+
+        // First set the receivers term to lower number
+        context.getTermInformation().update(1, "test");
 
+        // Prepare the receivers log
+        MockRaftActorContext.SimpleReplicatedLog log = new MockRaftActorContext.SimpleReplicatedLog();
+        log.append(newReplicatedLogEntry(1, 0, "zero"));
+        log.append(newReplicatedLogEntry(1, 1, "one"));
+        log.append(newReplicatedLogEntry(1, 2, "two"));
 
+        context.setReplicatedLog(log);
+
+        // Prepare the entries to be sent with AppendEntries
+        List<ReplicatedLogEntry> entries = new ArrayList<>();
+        entries.add(newReplicatedLogEntry(1, 3, "three"));
+        entries.add(newReplicatedLogEntry(1, 4, "four"));
+
+        // Send appendEntries with the same term as was set on the receiver
+        // before the new behavior was created (1 in this case)
+        // This will not work for a Candidate because as soon as a Candidate
+        // is created it increments the term
+        AppendEntries appendEntries = new AppendEntries(1, "leader-1", 2, 1, entries, 4, -1);
+
+        follower = createBehavior(context);
+
+        RaftActorBehavior newBehavior = follower.handleMessage(leaderActor, appendEntries);
+
+        Assert.assertSame(follower, newBehavior);
+
+        assertEquals("Next index", 5, log.last().getIndex() + 1);
+        assertEquals("Entry 3", entries.get(0), log.get(3));
+        assertEquals("Entry 4", entries.get(1), log.get(4));
+
+        expectAndVerifyAppendEntriesReply(1, true, context.getId(), 1, 4);
+    }
 
     /**
      * This test verifies that when a new AppendEntries message is received with
      * new entries and the logs of the sender and receiver are out-of-sync that
      * the log is first corrected by removing the out of sync entries from the
      * log and then adding in the new entries sent with the AppendEntries message
-     *
-     * @throws Exception
      */
     @Test
-    public void testHandleAppendEntriesCorrectReceiverLogEntries()
-        throws Exception {
-        new JavaTestKit(getSystem()) {{
-
-            MockRaftActorContext context = (MockRaftActorContext)
-                createActorContext();
-
-            // First set the receivers term to lower number
-            context.getTermInformation().update(2, "test");
-
-            // Prepare the receivers log
-            MockRaftActorContext.SimpleReplicatedLog log =
-                new MockRaftActorContext.SimpleReplicatedLog();
-            log.append(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero")));
-            log.append(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("one")));
-            log.append(
-                new MockRaftActorContext.MockReplicatedLogEntry(1, 2, new MockRaftActorContext.MockPayload("two")));
-
-            context.setReplicatedLog(log);
-
-            // Prepare the entries to be sent with AppendEntries
-            List<ReplicatedLogEntry> entries = new ArrayList<>();
-            entries.add(
-                new MockRaftActorContext.MockReplicatedLogEntry(2, 2, new MockRaftActorContext.MockPayload("two-1")));
-            entries.add(
-                new MockRaftActorContext.MockReplicatedLogEntry(2, 3, new MockRaftActorContext.MockPayload("three")));
-
-            // Send appendEntries with the same term as was set on the receiver
-            // before the new behavior was created (1 in this case)
-            // This will not work for a Candidate because as soon as a Candidate
-            // is created it increments the term
-            AppendEntries appendEntries =
-                new AppendEntries(2, "leader-1", 1, 1, entries, 3, -1);
-
-            RaftActorBehavior behavior = createBehavior(context);
-
-            // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
-
-            RaftActorBehavior raftBehavior =
-                behavior.handleMessage(getRef(), appendEntries);
-
-            assertEquals(expected, raftBehavior);
-
-            // The entry at index 2 will be found out-of-sync with the leader
-            // and will be removed
-            // Then the two new entries will be added to the log
-            // Thus making the log to have 4 entries
-            assertEquals(4, log.last().getIndex() + 1);
-            assertNotNull(log.get(2));
-
-            assertEquals("one", log.get(1).getData().toString());
-
-            // Check that the entry at index 2 has the new data
-            assertEquals("two-1", log.get(2).getData().toString());
-
-            assertEquals("three", log.get(3).getData().toString());
-
-            assertNotNull(log.get(3));
-
-            // Also expect an AppendEntriesReply to be sent where success is false
-            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
-                "AppendEntriesReply") {
-                // do not put code outside this method, will run afterwards
-                protected Boolean match(Object in) {
-                    if (in instanceof AppendEntriesReply) {
-                        AppendEntriesReply reply = (AppendEntriesReply) in;
-                        return reply.isSuccess();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get();
-
-            assertEquals(true, out);
-
-
-        }};
+    public void testHandleAppendEntriesCorrectReceiverLogEntries() {
+        logStart("testHandleAppendEntriesCorrectReceiverLogEntries");
+
+        MockRaftActorContext context = createActorContext();
+
+        // First set the receivers term to lower number
+        context.getTermInformation().update(1, "test");
+
+        // Prepare the receivers log
+        MockRaftActorContext.SimpleReplicatedLog log = new MockRaftActorContext.SimpleReplicatedLog();
+        log.append(newReplicatedLogEntry(1, 0, "zero"));
+        log.append(newReplicatedLogEntry(1, 1, "one"));
+        log.append(newReplicatedLogEntry(1, 2, "two"));
+
+        context.setReplicatedLog(log);
+
+        // Prepare the entries to be sent with AppendEntries
+        List<ReplicatedLogEntry> entries = new ArrayList<>();
+        entries.add(newReplicatedLogEntry(2, 2, "two-1"));
+        entries.add(newReplicatedLogEntry(2, 3, "three"));
+
+        // Send appendEntries with the same term as was set on the receiver
+        // before the new behavior was created (1 in this case)
+        // This will not work for a Candidate because as soon as a Candidate
+        // is created it increments the term
+        AppendEntries appendEntries = new AppendEntries(2, "leader", 1, 1, entries, 3, -1);
+
+        follower = createBehavior(context);
+
+        RaftActorBehavior newBehavior = follower.handleMessage(leaderActor, appendEntries);
+
+        Assert.assertSame(follower, newBehavior);
+
+        // The entry at index 2 will be found out-of-sync with the leader
+        // and will be removed
+        // Then the two new entries will be added to the log
+        // Thus making the log to have 4 entries
+        assertEquals("Next index", 4, log.last().getIndex() + 1);
+        //assertEquals("Entry 2", entries.get(0), log.get(2));
+
+        assertEquals("Entry 1 data", "one", log.get(1).getData().toString());
+
+        // Check that the entry at index 2 has the new data
+        assertEquals("Entry 2", entries.get(0), log.get(2));
+
+        assertEquals("Entry 3", entries.get(1), log.get(3));
+
+        expectAndVerifyAppendEntriesReply(2, true, context.getId(), 2, 3);
     }
 
     @Test
     public void testHandleAppendEntriesPreviousLogEntryMissing(){
-        new JavaTestKit(getSystem()) {{
+        logStart("testHandleAppendEntriesPreviousLogEntryMissing");
 
-            MockRaftActorContext context = (MockRaftActorContext)
-                    createActorContext();
+        MockRaftActorContext context = createActorContext();
 
-            // Prepare the receivers log
-            MockRaftActorContext.SimpleReplicatedLog log =
-                    new MockRaftActorContext.SimpleReplicatedLog();
-            log.append(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero")));
-            log.append(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("one")));
-            log.append(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 2, new MockRaftActorContext.MockPayload("two")));
+        // Prepare the receivers log
+        MockRaftActorContext.SimpleReplicatedLog log = new MockRaftActorContext.SimpleReplicatedLog();
+        log.append(newReplicatedLogEntry(1, 0, "zero"));
+        log.append(newReplicatedLogEntry(1, 1, "one"));
+        log.append(newReplicatedLogEntry(1, 2, "two"));
 
-            context.setReplicatedLog(log);
+        context.setReplicatedLog(log);
 
-            // Prepare the entries to be sent with AppendEntries
-            List<ReplicatedLogEntry> entries = new ArrayList<>();
-            entries.add(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 4, new MockRaftActorContext.MockPayload("two-1")));
+        // Prepare the entries to be sent with AppendEntries
+        List<ReplicatedLogEntry> entries = new ArrayList<>();
+        entries.add(newReplicatedLogEntry(1, 4, "four"));
 
-            AppendEntries appendEntries =
-                    new AppendEntries(1, "leader-1", 3, 1, entries, 4, -1);
+        AppendEntries appendEntries = new AppendEntries(1, "leader", 3, 1, entries, 4, -1);
 
-            RaftActorBehavior behavior = createBehavior(context);
+        follower = createBehavior(context);
 
-            // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
+        RaftActorBehavior newBehavior = follower.handleMessage(leaderActor, appendEntries);
 
-            RaftActorBehavior raftBehavior =
-                    behavior.handleMessage(getRef(), appendEntries);
+        Assert.assertSame(follower, newBehavior);
 
-            assertEquals(expected, raftBehavior);
+        expectAndVerifyAppendEntriesReply(1, false, context.getId(), 1, 2);
+    }
 
-            // Also expect an AppendEntriesReply to be sent where success is false
-            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
-                    "AppendEntriesReply") {
-                // do not put code outside this method, will run afterwards
-                protected Boolean match(Object in) {
-                    if (in instanceof AppendEntriesReply) {
-                        AppendEntriesReply reply = (AppendEntriesReply) in;
-                        return reply.isSuccess();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get();
+    @Test
+    public void testHandleAppendEntriesWithExistingLogEntry() {
+        logStart("testHandleAppendEntriesWithExistingLogEntry");
 
-            assertEquals(false, out);
+        MockRaftActorContext context = createActorContext();
 
-        }};
+        context.getTermInformation().update(1, "test");
 
-    }
+        // Prepare the receivers log
+        MockRaftActorContext.SimpleReplicatedLog log = new MockRaftActorContext.SimpleReplicatedLog();
+        log.append(newReplicatedLogEntry(1, 0, "zero"));
+        log.append(newReplicatedLogEntry(1, 1, "one"));
 
-    @Test
-    public void testHandleAppendAfterInstallingSnapshot(){
-        new JavaTestKit(getSystem()) {{
+        context.setReplicatedLog(log);
 
-            MockRaftActorContext context = (MockRaftActorContext)
-                    createActorContext();
+        // Send the last entry again.
+        List<ReplicatedLogEntry> entries = Arrays.asList(newReplicatedLogEntry(1, 1, "one"));
 
+        follower = createBehavior(context);
 
-            // Prepare the receivers log
-            MockRaftActorContext.SimpleReplicatedLog log =
-                    new MockRaftActorContext.SimpleReplicatedLog();
+        follower.handleMessage(leaderActor, new AppendEntries(1, "leader", 0, 1, entries, 1, -1));
 
-            // Set up a log as if it has been snapshotted
-            log.setSnapshotIndex(3);
-            log.setSnapshotTerm(1);
+        assertEquals("Next index", 2, log.last().getIndex() + 1);
+        assertEquals("Entry 1", entries.get(0), log.get(1));
 
-            context.setReplicatedLog(log);
+        expectAndVerifyAppendEntriesReply(1, true, context.getId(), 1, 1);
 
-            // Prepare the entries to be sent with AppendEntries
-            List<ReplicatedLogEntry> entries = new ArrayList<>();
-            entries.add(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 4, new MockRaftActorContext.MockPayload("two-1")));
+        // Send the last entry again and also a new one.
 
-            AppendEntries appendEntries =
-                    new AppendEntries(1, "leader-1", 3, 1, entries, 4, 3);
+        entries = Arrays.asList(newReplicatedLogEntry(1, 1, "one"), newReplicatedLogEntry(1, 2, "two"));
 
-            RaftActorBehavior behavior = createBehavior(context);
+        leaderActor.underlyingActor().clear();
+        follower.handleMessage(leaderActor, new AppendEntries(1, "leader", 0, 1, entries, 2, -1));
 
-            // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
+        assertEquals("Next index", 3, log.last().getIndex() + 1);
+        assertEquals("Entry 1", entries.get(0), log.get(1));
+        assertEquals("Entry 2", entries.get(1), log.get(2));
 
-            RaftActorBehavior raftBehavior =
-                    behavior.handleMessage(getRef(), appendEntries);
+        expectAndVerifyAppendEntriesReply(1, true, context.getId(), 1, 2);
+    }
 
-            assertEquals(expected, raftBehavior);
+    @Test
+    public void testHandleAppendAfterInstallingSnapshot(){
+        logStart("testHandleAppendAfterInstallingSnapshot");
 
-            // Also expect an AppendEntriesReply to be sent where success is false
-            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
-                    "AppendEntriesReply") {
-                // do not put code outside this method, will run afterwards
-                protected Boolean match(Object in) {
-                    if (in instanceof AppendEntriesReply) {
-                        AppendEntriesReply reply = (AppendEntriesReply) in;
-                        return reply.isSuccess();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get();
+        MockRaftActorContext context = createActorContext();
 
-            assertEquals(true, out);
+        // Prepare the receivers log
+        MockRaftActorContext.SimpleReplicatedLog log = new MockRaftActorContext.SimpleReplicatedLog();
 
-        }};
+        // Set up a log as if it has been snapshotted
+        log.setSnapshotIndex(3);
+        log.setSnapshotTerm(1);
 
+        context.setReplicatedLog(log);
+
+        // Prepare the entries to be sent with AppendEntries
+        List<ReplicatedLogEntry> entries = new ArrayList<>();
+        entries.add(newReplicatedLogEntry(1, 4, "four"));
+
+        AppendEntries appendEntries = new AppendEntries(1, "leader", 3, 1, entries, 4, 3);
+
+        follower = createBehavior(context);
+
+        RaftActorBehavior newBehavior = follower.handleMessage(leaderActor, appendEntries);
+
+        Assert.assertSame(follower, newBehavior);
+
+        expectAndVerifyAppendEntriesReply(1, true, context.getId(), 1, 4);
     }
 
 
@@ -543,182 +396,137 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
      */
     @Test
     public void testHandleInstallSnapshot() throws Exception {
-        JavaTestKit javaTestKit = new JavaTestKit(getSystem()) {{
-
-            ActorRef leaderActor = getSystem().actorOf(Props.create(
-                MessageCollectorActor.class));
-
-            MockRaftActorContext context = (MockRaftActorContext)
-                createActorContext(getRef());
-
-            Follower follower = (Follower)createBehavior(context);
-
-            HashMap<String, String> followerSnapshot = new HashMap<>();
-            followerSnapshot.put("1", "A");
-            followerSnapshot.put("2", "B");
-            followerSnapshot.put("3", "C");
-
-            ByteString bsSnapshot  = toByteString(followerSnapshot);
-            ByteString chunkData = ByteString.EMPTY;
-            int offset = 0;
-            int snapshotLength = bsSnapshot.size();
-            int i = 1;
-            int chunkIndex = 1;
-
-            do {
-                chunkData = getNextChunk(bsSnapshot, offset);
-                final InstallSnapshot installSnapshot =
-                    new InstallSnapshot(1, "leader-1", i, 1,
-                        chunkData, chunkIndex, 3);
-                follower.handleMessage(leaderActor, installSnapshot);
-                offset = offset + 50;
-                i++;
-                chunkIndex++;
-            } while ((offset+50) < snapshotLength);
-
-            final InstallSnapshot installSnapshot3 = new InstallSnapshot(1, "leader-1", 3, 1, chunkData, chunkIndex, 3);
-            follower.handleMessage(leaderActor, installSnapshot3);
-
-            String[] matches = new ReceiveWhile<String>(String.class, duration("2 seconds")) {
-                @Override
-                protected String match(Object o) throws Exception {
-                    if (o instanceof ApplySnapshot) {
-                        ApplySnapshot as = (ApplySnapshot)o;
-                        if (as.getSnapshot().getLastIndex() != installSnapshot3.getLastIncludedIndex()) {
-                            return "applySnapshot-lastIndex-mismatch";
-                        }
-                        if (as.getSnapshot().getLastAppliedTerm() != installSnapshot3.getLastIncludedTerm()) {
-                            return "applySnapshot-lastAppliedTerm-mismatch";
-                        }
-                        if (as.getSnapshot().getLastAppliedIndex() != installSnapshot3.getLastIncludedIndex()) {
-                            return "applySnapshot-lastAppliedIndex-mismatch";
-                        }
-                        if (as.getSnapshot().getLastTerm() != installSnapshot3.getLastIncludedTerm()) {
-                            return "applySnapshot-lastTerm-mismatch";
-                        }
-                        return "applySnapshot";
-                    }
-
-                    return "ignoreCase";
-                }
-            }.get();
-
-            // Verify that after a snapshot is successfully applied the collected snapshot chunks is reset to empty
-            assertEquals(ByteString.EMPTY, follower.getSnapshotChunksCollected());
-
-            String applySnapshotMatch = "";
-            for (String reply: matches) {
-                if (reply.startsWith("applySnapshot")) {
-                    applySnapshotMatch = reply;
-                }
-            }
-
-            assertEquals("applySnapshot", applySnapshotMatch);
-
-            Object messages = executeLocalOperation(leaderActor, "get-all-messages");
-
-            assertNotNull(messages);
-            assertTrue(messages instanceof List);
-            List<Object> listMessages = (List<Object>) messages;
-
-            int installSnapshotReplyReceivedCount = 0;
-            for (Object message: listMessages) {
-                if (message instanceof InstallSnapshotReply) {
-                    ++installSnapshotReplyReceivedCount;
-                }
-            }
+        logStart("testHandleInstallSnapshot");
+
+        MockRaftActorContext context = createActorContext();
+
+        follower = createBehavior(context);
+
+        HashMap<String, String> followerSnapshot = new HashMap<>();
+        followerSnapshot.put("1", "A");
+        followerSnapshot.put("2", "B");
+        followerSnapshot.put("3", "C");
+
+        ByteString bsSnapshot  = toByteString(followerSnapshot);
+        int offset = 0;
+        int snapshotLength = bsSnapshot.size();
+        int chunkSize = 50;
+        int totalChunks = (snapshotLength / chunkSize) + ((snapshotLength % chunkSize) > 0 ? 1 : 0);
+        int lastIncludedIndex = 1;
+        int chunkIndex = 1;
+        InstallSnapshot lastInstallSnapshot = null;
+
+        for(int i = 0; i < totalChunks; i++) {
+            ByteString chunkData = getNextChunk(bsSnapshot, offset, chunkSize);
+            lastInstallSnapshot = new InstallSnapshot(1, "leader", lastIncludedIndex, 1,
+                    chunkData, chunkIndex, totalChunks);
+            follower.handleMessage(leaderActor, lastInstallSnapshot);
+            offset = offset + 50;
+            lastIncludedIndex++;
+            chunkIndex++;
+        }
 
-            assertEquals(3, installSnapshotReplyReceivedCount);
+        ApplySnapshot applySnapshot = MessageCollectorActor.expectFirstMatching(followerActor,
+                ApplySnapshot.class);
+        Snapshot snapshot = applySnapshot.getSnapshot();
+        assertEquals("getLastIndex", lastInstallSnapshot.getLastIncludedIndex(), snapshot.getLastIndex());
+        assertEquals("getLastIncludedTerm", lastInstallSnapshot.getLastIncludedTerm(),
+                snapshot.getLastAppliedTerm());
+        assertEquals("getLastAppliedIndex", lastInstallSnapshot.getLastIncludedIndex(),
+                snapshot.getLastAppliedIndex());
+        assertEquals("getLastTerm", lastInstallSnapshot.getLastIncludedTerm(), snapshot.getLastTerm());
+        Assert.assertArrayEquals("getState", bsSnapshot.toByteArray(), snapshot.getState());
+
+        List<InstallSnapshotReply> replies = MessageCollectorActor.getAllMatching(
+                leaderActor, InstallSnapshotReply.class);
+        assertEquals("InstallSnapshotReply count", totalChunks, replies.size());
+
+        chunkIndex = 1;
+        for(InstallSnapshotReply reply: replies) {
+            assertEquals("getChunkIndex", chunkIndex++, reply.getChunkIndex());
+            assertEquals("getTerm", 1, reply.getTerm());
+            assertEquals("isSuccess", true, reply.isSuccess());
+            assertEquals("getFollowerId", context.getId(), reply.getFollowerId());
+        }
 
-        }};
+        Assert.assertNull("Expected null SnapshotTracker", ((Follower)follower).getSnapshotTracker());
     }
 
     @Test
     public void testHandleOutOfSequenceInstallSnapshot() throws Exception {
-        JavaTestKit javaTestKit = new JavaTestKit(getSystem()) {
-            {
-
-                ActorRef leaderActor = getSystem().actorOf(Props.create(
-                        MessageCollectorActor.class));
-
-                MockRaftActorContext context = (MockRaftActorContext)
-                        createActorContext(getRef());
+        logStart("testHandleOutOfSequenceInstallSnapshot");
 
-                Follower follower = (Follower) createBehavior(context);
+        MockRaftActorContext context = createActorContext();
 
-                HashMap<String, String> followerSnapshot = new HashMap<>();
-                followerSnapshot.put("1", "A");
-                followerSnapshot.put("2", "B");
-                followerSnapshot.put("3", "C");
+        follower = createBehavior(context);
 
-                ByteString bsSnapshot = toByteString(followerSnapshot);
+        HashMap<String, String> followerSnapshot = new HashMap<>();
+        followerSnapshot.put("1", "A");
+        followerSnapshot.put("2", "B");
+        followerSnapshot.put("3", "C");
 
-                final InstallSnapshot installSnapshot = new InstallSnapshot(1, "leader-1", 3, 1, getNextChunk(bsSnapshot, 10), 3, 3);
-                follower.handleMessage(leaderActor, installSnapshot);
+        ByteString bsSnapshot = toByteString(followerSnapshot);
 
-                Object messages = executeLocalOperation(leaderActor, "get-all-messages");
+        InstallSnapshot installSnapshot = new InstallSnapshot(1, "leader", 3, 1,
+                getNextChunk(bsSnapshot, 10, 50), 3, 3);
+        follower.handleMessage(leaderActor, installSnapshot);
 
-                assertNotNull(messages);
-                assertTrue(messages instanceof List);
-                List<Object> listMessages = (List<Object>) messages;
+        InstallSnapshotReply reply = MessageCollectorActor.expectFirstMatching(leaderActor,
+                InstallSnapshotReply.class);
 
-                int installSnapshotReplyReceivedCount = 0;
-                for (Object message: listMessages) {
-                    if (message instanceof InstallSnapshotReply) {
-                        ++installSnapshotReplyReceivedCount;
-                    }
-                }
+        assertEquals("isSuccess", false, reply.isSuccess());
+        assertEquals("getChunkIndex", -1, reply.getChunkIndex());
+        assertEquals("getTerm", 1, reply.getTerm());
+        assertEquals("getFollowerId", context.getId(), reply.getFollowerId());
 
-                assertEquals(1, installSnapshotReplyReceivedCount);
-                InstallSnapshotReply reply = (InstallSnapshotReply) listMessages.get(0);
-                assertEquals(false, reply.isSuccess());
-                assertEquals(-1, reply.getChunkIndex());
-                assertEquals(ByteString.EMPTY, follower.getSnapshotChunksCollected());
-
-
-            }};
+        Assert.assertNull("Expected null SnapshotTracker", ((Follower)follower).getSnapshotTracker());
     }
 
-    public Object executeLocalOperation(ActorRef actor, Object message) throws Exception {
-        return MessageCollectorActor.getAllMessages(actor);
-    }
-
-    public ByteString getNextChunk (ByteString bs, int offset){
+    public ByteString getNextChunk (ByteString bs, int offset, int chunkSize){
         int snapshotLength = bs.size();
         int start = offset;
-        int size = 50;
-        if (50 > snapshotLength) {
+        int size = chunkSize;
+        if (chunkSize > snapshotLength) {
             size = snapshotLength;
         } else {
-            if ((start + 50) > snapshotLength) {
+            if ((start + chunkSize) > snapshotLength) {
                 size = snapshotLength - start;
             }
         }
         return bs.substring(start, start + size);
     }
 
-    private ByteString toByteString(Map<String, String> state) {
-        ByteArrayOutputStream b = null;
-        ObjectOutputStream o = null;
-        try {
-            try {
-                b = new ByteArrayOutputStream();
-                o = new ObjectOutputStream(b);
-                o.writeObject(state);
-                byte[] snapshotBytes = b.toByteArray();
-                return ByteString.copyFrom(snapshotBytes);
-            } finally {
-                if (o != null) {
-                    o.flush();
-                    o.close();
-                }
-                if (b != null) {
-                    b.close();
-                }
-            }
-        } catch (IOException e) {
-            org.junit.Assert.fail("IOException in converting Hashmap to Bytestring:" + e);
-        }
-        return null;
+    private void expectAndVerifyAppendEntriesReply(int expTerm, boolean expSuccess,
+            String expFollowerId, long expLogLastTerm, long expLogLastIndex) {
+
+        AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(leaderActor,
+                AppendEntriesReply.class);
+
+        assertEquals("isSuccess", expSuccess, reply.isSuccess());
+        assertEquals("getTerm", expTerm, reply.getTerm());
+        assertEquals("getFollowerId", expFollowerId, reply.getFollowerId());
+        assertEquals("getLogLastTerm", expLogLastTerm, reply.getLogLastTerm());
+        assertEquals("getLogLastIndex", expLogLastIndex, reply.getLogLastIndex());
+    }
+
+    private ReplicatedLogEntry newReplicatedLogEntry(long term, long index, String data) {
+        return new MockRaftActorContext.MockReplicatedLogEntry(term, index,
+                new MockRaftActorContext.MockPayload(data));
+    }
+
+    @Override
+    protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(RaftActorContext actorContext,
+            ActorRef actorRef, RaftRPC rpc) throws Exception {
+        super.assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, actorRef, rpc);
+
+        String expVotedFor = RequestVote.class.isInstance(rpc) ? ((RequestVote)rpc).getCandidateId() : null;
+        assertEquals("New votedFor", expVotedFor, actorContext.getTermInformation().getVotedFor());
+    }
+
+    @Override
+    protected void handleAppendEntriesAddSameEntryToLogReply(TestActorRef<MessageCollectorActor> replyActor)
+            throws Exception {
+        AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(replyActor, AppendEntriesReply.class);
+        assertEquals("isSuccess", true, reply.isSuccess());
     }
 }
index 708068a78952db5ba287501c1a534a31721556ad..e16d765cdea29a76b0a18440a3128c1a4f2529e6 100644 (file)
  */
 package org.opendaylight.controller.cluster.raft.behaviors;
 
+import static org.junit.Assert.assertEquals;
 import akka.actor.ActorRef;
 import akka.actor.Props;
-import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
 import java.util.HashMap;
 import java.util.Map;
+import org.junit.After;
 import org.junit.Test;
+import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftState;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
-import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
+
+public class IsolatedLeaderTest  extends AbstractLeaderTest {
+
+    private final TestActorRef<MessageCollectorActor> leaderActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("leader"));
 
-public class IsolatedLeaderTest  extends AbstractRaftActorBehaviorTest {
+    private final TestActorRef<MessageCollectorActor> senderActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("sender"));
 
-    private ActorRef leaderActor =
-        getSystem().actorOf(Props.create(DoNothingActor.class));
+    private AbstractLeader isolatedLeader;
 
-    private ActorRef senderActor =
-        getSystem().actorOf(Props.create(DoNothingActor.class));
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        if(isolatedLeader != null) {
+            isolatedLeader.close();
+        }
+
+        super.tearDown();
+    }
 
     @Override
-    protected RaftActorBehavior createBehavior(
-        RaftActorContext actorContext) {
-        return new Leader(actorContext);
+    protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
+        return new IsolatedLeader(actorContext);
     }
 
     @Override
-    protected RaftActorContext createActorContext() {
+    protected MockRaftActorContext createActorContext() {
         return createActorContext(leaderActor);
     }
 
+    @Override
+    protected MockRaftActorContext createActorContext(ActorRef actor) {
+        DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
+        configParams.setElectionTimeoutFactor(100000);
+        MockRaftActorContext context = new MockRaftActorContext("isolated-leader", getSystem(), actor);
+        context.setConfigParams(configParams);
+        return context;
+    }
 
     @Test
-    public void testHandleMessageWithThreeMembers() {
-        new JavaTestKit(getSystem()) {{
-            String followerAddress1 = "akka://test/user/$a";
-            String followerAddress2 = "akka://test/user/$b";
-
-            MockRaftActorContext leaderActorContext = (MockRaftActorContext) createActorContext();
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower-1", followerAddress1);
-            peerAddresses.put("follower-2", followerAddress2);
-            leaderActorContext.setPeerAddresses(peerAddresses);
-
-            IsolatedLeader isolatedLeader = new IsolatedLeader(leaderActorContext);
-            assertTrue(isolatedLeader.state() == RaftState.IsolatedLeader);
-
-            // in a 3 node cluster, even if 1 follower is returns a reply, the isolatedLeader is not isolated
-            RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
+    public void testHandleMessageWithThreeMembers() throws Exception {
+        String followerAddress1 = "akka://test/user/$a";
+        String followerAddress2 = "akka://test/user/$b";
+
+        MockRaftActorContext leaderActorContext = createActorContext();
+        Map<String, String> peerAddresses = new HashMap<>();
+        peerAddresses.put("follower-1", followerAddress1);
+        peerAddresses.put("follower-2", followerAddress2);
+        leaderActorContext.setPeerAddresses(peerAddresses);
+
+        isolatedLeader = new IsolatedLeader(leaderActorContext);
+        assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
+
+        // in a 3 node cluster, even if 1 follower is returns a reply, the isolatedLeader is not isolated
+        RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
                 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
-                    isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1));
+                        isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1));
+
+        assertEquals("Raft state", RaftState.Leader, behavior.state());
 
-            assertEquals(RaftState.Leader, behavior.state());
+        isolatedLeader.close();
+        isolatedLeader = (AbstractLeader) behavior;
 
-            behavior = isolatedLeader.handleMessage(senderActor,
+        behavior = isolatedLeader.handleMessage(senderActor,
                 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
-                    isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
+                        isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
 
-            assertEquals(RaftState.Leader, behavior.state());
-        }};
+        assertEquals("Raft state", RaftState.Leader, behavior.state());
     }
 
     @Test
-    public void testHandleMessageWithFiveMembers() {
-        new JavaTestKit(getSystem()) {{
-
-            String followerAddress1 = "akka://test/user/$a";
-            String followerAddress2 = "akka://test/user/$b";
-            String followerAddress3 = "akka://test/user/$c";
-            String followerAddress4 = "akka://test/user/$d";
-
-            MockRaftActorContext leaderActorContext = (MockRaftActorContext) createActorContext();
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower-1", followerAddress1);
-            peerAddresses.put("follower-2", followerAddress2);
-            peerAddresses.put("follower-3", followerAddress3);
-            peerAddresses.put("follower-4", followerAddress4);
-            leaderActorContext.setPeerAddresses(peerAddresses);
-
-            IsolatedLeader isolatedLeader = new IsolatedLeader(leaderActorContext);
-            assertEquals(RaftState.IsolatedLeader, isolatedLeader.state());
-
-            // in a 5 member cluster, atleast 2 followers need to be active and return a reply
-            RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
+    public void testHandleMessageWithFiveMembers() throws Exception {
+        String followerAddress1 = "akka://test/user/$a";
+        String followerAddress2 = "akka://test/user/$b";
+        String followerAddress3 = "akka://test/user/$c";
+        String followerAddress4 = "akka://test/user/$d";
+
+        MockRaftActorContext leaderActorContext = createActorContext();
+        Map<String, String> peerAddresses = new HashMap<>();
+        peerAddresses.put("follower-1", followerAddress1);
+        peerAddresses.put("follower-2", followerAddress2);
+        peerAddresses.put("follower-3", followerAddress3);
+        peerAddresses.put("follower-4", followerAddress4);
+        leaderActorContext.setPeerAddresses(peerAddresses);
+
+        isolatedLeader = new IsolatedLeader(leaderActorContext);
+        assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
+
+        // in a 5 member cluster, atleast 2 followers need to be active and return a reply
+        RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
                 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
-                    isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
+                        isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
 
-            assertEquals(RaftState.IsolatedLeader, behavior.state());
+        assertEquals("Raft state", RaftState.IsolatedLeader, behavior.state());
 
-            behavior = isolatedLeader.handleMessage(senderActor,
+        behavior = isolatedLeader.handleMessage(senderActor,
                 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
-                    isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
+                        isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
+
+        assertEquals("Raft state", RaftState.Leader, behavior.state());
 
-            assertEquals(RaftState.Leader, behavior.state());
+        isolatedLeader.close();
+        isolatedLeader = (AbstractLeader) behavior;
 
-            behavior = isolatedLeader.handleMessage(senderActor,
+        behavior = isolatedLeader.handleMessage(senderActor,
                 new AppendEntriesReply("follower-3", isolatedLeader.lastTerm() - 1, true,
-                    isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
+                        isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
 
-            assertEquals(RaftState.Leader, behavior.state());
-        }};
+        assertEquals("Raft state", RaftState.Leader, behavior.state());
     }
 
     @Test
-    public void testHandleMessageFromAnotherLeader() {
-        new JavaTestKit(getSystem()) {{
-            String followerAddress1 = "akka://test/user/$a";
-            String followerAddress2 = "akka://test/user/$b";
-
-            MockRaftActorContext leaderActorContext = (MockRaftActorContext) createActorContext();
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower-1", followerAddress1);
-            peerAddresses.put("follower-2", followerAddress2);
-            leaderActorContext.setPeerAddresses(peerAddresses);
-
-            IsolatedLeader isolatedLeader = new IsolatedLeader(leaderActorContext);
-            assertTrue(isolatedLeader.state() == RaftState.IsolatedLeader);
-
-            // if an append-entries reply is received by the isolated-leader, and that reply
-            // has a term  > than its own term, then IsolatedLeader switches to Follower
-            // bowing itself to another leader in the cluster
-            RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
+    public void testHandleMessageFromAnotherLeader() throws Exception {
+        String followerAddress1 = "akka://test/user/$a";
+        String followerAddress2 = "akka://test/user/$b";
+
+        MockRaftActorContext leaderActorContext = createActorContext();
+        Map<String, String> peerAddresses = new HashMap<>();
+        peerAddresses.put("follower-1", followerAddress1);
+        peerAddresses.put("follower-2", followerAddress2);
+        leaderActorContext.setPeerAddresses(peerAddresses);
+
+        isolatedLeader = new IsolatedLeader(leaderActorContext);
+        assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
+
+        // if an append-entries reply is received by the isolated-leader, and that reply
+        // has a term  > than its own term, then IsolatedLeader switches to Follower
+        // bowing itself to another leader in the cluster
+        RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
                 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() + 1, true,
-                    isolatedLeader.lastIndex() + 1, isolatedLeader.lastTerm() + 1));
+                        isolatedLeader.lastIndex() + 1, isolatedLeader.lastTerm() + 1));
 
-            assertEquals(RaftState.Follower, behavior.state());
-        }};
+        assertEquals("Raft state", RaftState.Follower, behavior.state());
 
+        behavior.close();
     }
 }
index 119b958799e815d21b22c18dae11e9ff7415d928..c57fce1cd553d8c41dd786d9c4bb6f33e97791b6 100644 (file)
@@ -10,15 +10,14 @@ import akka.actor.Terminated;
 import akka.testkit.JavaTestKit;
 import akka.testkit.TestActorRef;
 import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.Uninterruptibles;
 import com.google.protobuf.ByteString;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
@@ -35,810 +34,653 @@ import org.opendaylight.controller.cluster.raft.base.messages.IsolatedLeaderChec
 import org.opendaylight.controller.cluster.raft.base.messages.Replicate;
 import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat;
 import org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot;
+import org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader.FollowerToSnapshot;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
 import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot;
 import org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply;
+import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
-import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
+import org.opendaylight.controller.cluster.raft.utils.ForwardMessageToBehaviorActor;
 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
 import org.opendaylight.controller.protobuff.messages.cluster.raft.InstallSnapshotMessages;
 import scala.concurrent.duration.FiniteDuration;
 
-public class LeaderTest extends AbstractRaftActorBehaviorTest {
+public class LeaderTest extends AbstractLeaderTest {
 
-    private final ActorRef leaderActor =
-        getSystem().actorOf(Props.create(DoNothingActor.class));
-    private final ActorRef senderActor =
-        getSystem().actorOf(Props.create(DoNothingActor.class));
+    static final String FOLLOWER_ID = "follower";
+
+    private final TestActorRef<ForwardMessageToBehaviorActor> leaderActor = actorFactory.createTestActor(
+            Props.create(ForwardMessageToBehaviorActor.class), actorFactory.generateActorId("leader"));
+
+    private final TestActorRef<ForwardMessageToBehaviorActor> followerActor = actorFactory.createTestActor(
+            Props.create(ForwardMessageToBehaviorActor.class), actorFactory.generateActorId("follower"));
+
+    private Leader leader;
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        if(leader != null) {
+            leader.close();
+        }
+
+        super.tearDown();
+    }
 
     @Test
     public void testHandleMessageForUnknownMessage() throws Exception {
-        new JavaTestKit(getSystem()) {{
-            Leader leader =
-                new Leader(createActorContext());
+        logStart("testHandleMessageForUnknownMessage");
 
-            // handle message should return the Leader state when it receives an
-            // unknown message
-            RaftActorBehavior behavior = leader.handleMessage(senderActor, "foo");
-            Assert.assertTrue(behavior instanceof Leader);
-        }};
+        leader = new Leader(createActorContext());
+
+        // handle message should return the Leader state when it receives an
+        // unknown message
+        RaftActorBehavior behavior = leader.handleMessage(followerActor, "foo");
+        Assert.assertTrue(behavior instanceof Leader);
     }
 
     @Test
-    public void testThatLeaderSendsAHeartbeatMessageToAllFollowers() {
-        new JavaTestKit(getSystem()) {{
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-                    ActorRef followerActor = getTestActor();
+    public void testThatLeaderSendsAHeartbeatMessageToAllFollowers() throws Exception {
+        logStart("testThatLeaderSendsAHeartbeatMessageToAllFollowers");
 
-                    MockRaftActorContext actorContext = (MockRaftActorContext) createActorContext();
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-                    Map<String, String> peerAddresses = new HashMap<>();
+        long term = 1;
+        actorContext.getTermInformation().update(term, "");
 
-                    String followerId = "follower";
-                    peerAddresses.put(followerId, followerActor.path().toString());
+        leader = new Leader(actorContext);
 
-                    actorContext.setPeerAddresses(peerAddresses);
+        // Leader should send an immediate heartbeat with no entries as follower is inactive.
+        long lastIndex = actorContext.getReplicatedLog().lastIndex();
+        AppendEntries appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
+        assertEquals("getTerm", term, appendEntries.getTerm());
+        assertEquals("getPrevLogIndex", -1, appendEntries.getPrevLogIndex());
+        assertEquals("getPrevLogTerm", -1, appendEntries.getPrevLogTerm());
+        assertEquals("Entries size", 0, appendEntries.getEntries().size());
 
-                    long term = 1;
-                    actorContext.getTermInformation().update(term, "");
+        // The follower would normally reply - simulate that explicitly here.
+        leader.handleMessage(followerActor, new AppendEntriesReply(
+                FOLLOWER_ID, term, true, lastIndex - 1, term));
+        assertEquals("isFollowerActive", true, leader.getFollower(FOLLOWER_ID).isFollowerActive());
 
-                    Leader leader = new Leader(actorContext);
+        followerActor.underlyingActor().clear();
 
-                    // Leader should send an immediate heartbeat with no entries as follower is inactive.
-                    long lastIndex = actorContext.getReplicatedLog().lastIndex();
-                    AppendEntries appendEntries = expectMsgClass(duration("5 seconds"), AppendEntries.class);
-                    assertEquals("getTerm", term, appendEntries.getTerm());
-                    assertEquals("getPrevLogIndex", -1, appendEntries.getPrevLogIndex());
-                    assertEquals("getPrevLogTerm", -1, appendEntries.getPrevLogTerm());
-                    assertEquals("Entries size", 0, appendEntries.getEntries().size());
+        // Sleep for the heartbeat interval so AppendEntries is sent.
+        Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().
+                getHeartBeatInterval().toMillis(), TimeUnit.MILLISECONDS);
 
-                    // The follower would normally reply - simulate that explicitly here.
-                    leader.handleMessage(followerActor, new AppendEntriesReply(
-                            followerId, term, true, lastIndex - 1, term));
-                    assertEquals("isFollowerActive", true, leader.getFollower(followerId).isFollowerActive());
+        leader.handleMessage(leaderActor, new SendHeartBeat());
 
-                    // Sleep for the heartbeat interval so AppendEntries is sent.
-                    Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().
-                            getHeartBeatInterval().toMillis(), TimeUnit.MILLISECONDS);
+        appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
+        assertEquals("getPrevLogIndex", lastIndex - 1, appendEntries.getPrevLogIndex());
+        assertEquals("getPrevLogTerm", term, appendEntries.getPrevLogTerm());
+        assertEquals("Entries size", 1, appendEntries.getEntries().size());
+        assertEquals("Entry getIndex", lastIndex, appendEntries.getEntries().get(0).getIndex());
+        assertEquals("Entry getTerm", term, appendEntries.getEntries().get(0).getTerm());
+    }
 
-                    leader.handleMessage(senderActor, new SendHeartBeat());
+    @Test
+    public void testHandleReplicateMessageSendAppendEntriesToFollower() throws Exception {
+        logStart("testHandleReplicateMessageSendAppendEntriesToFollower");
 
-                    appendEntries = expectMsgClass(duration("5 seconds"), AppendEntries.class);
-                    assertEquals("getPrevLogIndex", lastIndex - 1, appendEntries.getPrevLogIndex());
-                    assertEquals("getPrevLogTerm", term, appendEntries.getPrevLogTerm());
-                    assertEquals("Entries size", 1, appendEntries.getEntries().size());
-                    assertEquals("Entry getIndex", lastIndex, appendEntries.getEntries().get(0).getIndex());
-                    assertEquals("Entry getTerm", term, appendEntries.getEntries().get(0).getTerm());
-                }
-            };
-        }};
+        MockRaftActorContext actorContext = createActorContextWithFollower();
+
+        long term = 1;
+        actorContext.getTermInformation().update(term, "");
+
+        leader = new Leader(actorContext);
+
+        // Leader will send an immediate heartbeat - ignore it.
+        MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
+
+        // The follower would normally reply - simulate that explicitly here.
+        long lastIndex = actorContext.getReplicatedLog().lastIndex();
+        leader.handleMessage(followerActor, new AppendEntriesReply(
+                FOLLOWER_ID, term, true, lastIndex, term));
+        assertEquals("isFollowerActive", true, leader.getFollower(FOLLOWER_ID).isFollowerActive());
+
+        followerActor.underlyingActor().clear();
+
+        MockRaftActorContext.MockPayload payload = new MockRaftActorContext.MockPayload("foo");
+        MockRaftActorContext.MockReplicatedLogEntry newEntry = new MockRaftActorContext.MockReplicatedLogEntry(
+                1, lastIndex + 1, payload);
+        actorContext.getReplicatedLog().append(newEntry);
+        RaftActorBehavior raftBehavior = leader.handleMessage(leaderActor,
+                new Replicate(null, null, newEntry));
+
+        // State should not change
+        assertTrue(raftBehavior instanceof Leader);
+
+        AppendEntries appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
+        assertEquals("getPrevLogIndex", lastIndex, appendEntries.getPrevLogIndex());
+        assertEquals("getPrevLogTerm", term, appendEntries.getPrevLogTerm());
+        assertEquals("Entries size", 1, appendEntries.getEntries().size());
+        assertEquals("Entry getIndex", lastIndex + 1, appendEntries.getEntries().get(0).getIndex());
+        assertEquals("Entry getTerm", term, appendEntries.getEntries().get(0).getTerm());
+        assertEquals("Entry payload", payload, appendEntries.getEntries().get(0).getData());
     }
 
     @Test
-    public void testHandleReplicateMessageSendAppendEntriesToFollower() {
-        new JavaTestKit(getSystem()) {{
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-                    ActorRef followerActor = getTestActor();
+    public void testHandleReplicateMessageWhenThereAreNoFollowers() throws Exception {
+        logStart("testHandleReplicateMessageWhenThereAreNoFollowers");
 
-                    MockRaftActorContext actorContext = (MockRaftActorContext) createActorContext();
+        MockRaftActorContext actorContext = createActorContext();
 
-                    Map<String, String> peerAddresses = new HashMap<>();
+        leader = new Leader(actorContext);
 
-                    String followerId = "follower";
-                    peerAddresses.put(followerId, followerActor.path().toString());
+        actorContext.setLastApplied(0);
 
-                    actorContext.setPeerAddresses(peerAddresses);
+        long newLogIndex = actorContext.getReplicatedLog().lastIndex() + 1;
+        long term = actorContext.getTermInformation().getCurrentTerm();
+        MockRaftActorContext.MockReplicatedLogEntry newEntry = new MockRaftActorContext.MockReplicatedLogEntry(
+                term, newLogIndex, new MockRaftActorContext.MockPayload("foo"));
 
-                    long term = 1;
-                    actorContext.getTermInformation().update(term, "");
+        actorContext.getReplicatedLog().append(newEntry);
 
-                    Leader leader = new Leader(actorContext);
+        RaftActorBehavior raftBehavior = leader.handleMessage(leaderActor,
+                new Replicate(leaderActor, "state-id", newEntry));
 
-                    // Leader will send an immediate heartbeat - ignore it.
-                    expectMsgClass(duration("5 seconds"), AppendEntries.class);
+        // State should not change
+        assertTrue(raftBehavior instanceof Leader);
 
-                    // The follower would normally reply - simulate that explicitly here.
-                    long lastIndex = actorContext.getReplicatedLog().lastIndex();
-                    leader.handleMessage(followerActor, new AppendEntriesReply(
-                            followerId, term, true, lastIndex, term));
-                    assertEquals("isFollowerActive", true, leader.getFollower(followerId).isFollowerActive());
+        assertEquals("getCommitIndex", newLogIndex, actorContext.getCommitIndex());
 
-                    MockRaftActorContext.MockPayload payload = new MockRaftActorContext.MockPayload("foo");
-                    MockRaftActorContext.MockReplicatedLogEntry newEntry = new MockRaftActorContext.MockReplicatedLogEntry(
-                            1, lastIndex + 1, payload);
-                    actorContext.getReplicatedLog().append(newEntry);
-                    RaftActorBehavior raftBehavior = leader.handleMessage(senderActor,
-                            new Replicate(null, null, newEntry));
+        // We should get 2 ApplyState messages - 1 for new log entry and 1 for the previous
+        // one since lastApplied state is 0.
+        List<ApplyState> applyStateList = MessageCollectorActor.getAllMatching(
+                leaderActor, ApplyState.class);
+        assertEquals("ApplyState count", newLogIndex, applyStateList.size());
 
-                    // State should not change
-                    assertTrue(raftBehavior instanceof Leader);
-
-                    AppendEntries appendEntries = expectMsgClass(duration("5 seconds"), AppendEntries.class);
-                    assertEquals("getPrevLogIndex", lastIndex, appendEntries.getPrevLogIndex());
-                    assertEquals("getPrevLogTerm", term, appendEntries.getPrevLogTerm());
-                    assertEquals("Entries size", 1, appendEntries.getEntries().size());
-                    assertEquals("Entry getIndex", lastIndex + 1, appendEntries.getEntries().get(0).getIndex());
-                    assertEquals("Entry getTerm", term, appendEntries.getEntries().get(0).getTerm());
-                    assertEquals("Entry payload", payload, appendEntries.getEntries().get(0).getData());
-                }
-            };
-        }};
-    }
+        for(int i = 0; i <= newLogIndex - 1; i++ ) {
+            ApplyState applyState = applyStateList.get(i);
+            assertEquals("getIndex", i + 1, applyState.getReplicatedLogEntry().getIndex());
+            assertEquals("getTerm", term, applyState.getReplicatedLogEntry().getTerm());
+        }
 
-    @Test
-    public void testHandleReplicateMessageWhenThereAreNoFollowers() {
-        new JavaTestKit(getSystem()) {{
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    ActorRef raftActor = getTestActor();
-
-                    MockRaftActorContext actorContext =
-                        new MockRaftActorContext("test", getSystem(), raftActor);
-
-                    actorContext.getReplicatedLog().removeFrom(0);
-
-                    actorContext.setReplicatedLog(
-                        new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 2, 1)
-                            .build());
-
-                    Leader leader = new Leader(actorContext);
-                    RaftActorBehavior raftBehavior = leader
-                        .handleMessage(senderActor, new Replicate(null, "state-id",actorContext.getReplicatedLog().get(1)));
-
-                    // State should not change
-                    assertTrue(raftBehavior instanceof Leader);
-
-                    assertEquals(1, actorContext.getCommitIndex());
-
-                    final String out =
-                        new ExpectMsg<String>(duration("1 seconds"),
-                            "match hint") {
-                            // do not put code outside this method, will run afterwards
-                            @Override
-                            protected String match(Object in) {
-                                if (in instanceof ApplyState) {
-                                    if (((ApplyState) in).getIdentifier().equals("state-id")) {
-                                        return "match";
-                                    }
-                                    return null;
-                                } else {
-                                    throw noMatch();
-                                }
-                            }
-                        }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                }
-            };
-        }};
+        ApplyState last = applyStateList.get((int) newLogIndex - 1);
+        assertEquals("getData", newEntry.getData(), last.getReplicatedLogEntry().getData());
+        assertEquals("getIdentifier", "state-id", last.getIdentifier());
     }
 
     @Test
     public void testSendAppendEntriesOnAnInProgressInstallSnapshot() throws Exception {
-        new JavaTestKit(getSystem()) {{
-            ActorRef followerActor = getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        logStart("testSendAppendEntriesOnAnInProgressInstallSnapshot");
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put(followerActor.path().toString(),
-                followerActor.path().toString());
-
-            MockRaftActorContext actorContext =
-                (MockRaftActorContext) createActorContext(leaderActor);
-            actorContext.setPeerAddresses(peerAddresses);
-
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
-
-            //clears leaders log
-            actorContext.getReplicatedLog().removeFrom(0);
-
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int newEntryIndex = 4;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
-
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.setCommitIndex(followersLastIndex);
-            //set follower timeout to 2 mins, helps during debugging
-            actorContext.setConfigParams(new MockConfigParamsImpl(120000L, 10));
-
-            MockLeader leader = new MockLeader(actorContext);
-
-            // new entry
-            ReplicatedLogImplEntry entry =
-                new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
-                    new MockRaftActorContext.MockPayload("D"));
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            //update follower timestamp
-            leader.markFollowerActive(followerActor.path().toString());
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            ByteString bs = toByteString(leadersSnapshot);
-            leader.setSnapshot(Optional.of(bs));
-            leader.createFollowerToSnapshot(followerActor.path().toString(), bs);
+        //clears leaders log
+        actorContext.getReplicatedLog().removeFrom(0);
 
-            //send first chunk and no InstallSnapshotReply received yet
-            leader.getFollowerToSnapshot().getNextChunk();
-            leader.getFollowerToSnapshot().incrementChunkIndex();
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int newEntryIndex = 4;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(),
-                TimeUnit.MILLISECONDS);
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.setCommitIndex(followersLastIndex);
+        //set follower timeout to 2 mins, helps during debugging
+        actorContext.setConfigParams(new MockConfigParamsImpl(120000L, 10));
 
-            leader.handleMessage(leaderActor, new SendHeartBeat());
+        leader = new Leader(actorContext);
 
-            AppendEntries aeproto = MessageCollectorActor.getFirstMatching(
-                followerActor, AppendEntries.class);
+        // new entry
+        ReplicatedLogImplEntry entry =
+                new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
+                        new MockRaftActorContext.MockPayload("D"));
 
-            assertNotNull("AppendEntries should be sent even if InstallSnapshotReply is not " +
-                "received", aeproto);
+        //update follower timestamp
+        leader.markFollowerActive(FOLLOWER_ID);
 
-            AppendEntries ae = (AppendEntries) SerializationUtils.fromSerializable(aeproto);
+        ByteString bs = toByteString(leadersSnapshot);
+        leader.setSnapshot(Optional.of(bs));
+        FollowerToSnapshot fts = leader.new FollowerToSnapshot(bs);
+        leader.setFollowerSnapshot(FOLLOWER_ID, fts);
 
-            assertTrue("AppendEntries should be sent with empty entries", ae.getEntries().isEmpty());
+        //send first chunk and no InstallSnapshotReply received yet
+        fts.getNextChunk();
+        fts.incrementChunkIndex();
 
-            //InstallSnapshotReply received
-            leader.getFollowerToSnapshot().markSendStatus(true);
+        Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(),
+                TimeUnit.MILLISECONDS);
 
-            leader.handleMessage(senderActor, new SendHeartBeat());
+        leader.handleMessage(leaderActor, new SendHeartBeat());
 
-            InstallSnapshotMessages.InstallSnapshot isproto = MessageCollectorActor.getFirstMatching(followerActor,
-                InstallSnapshot.SERIALIZABLE_CLASS);
+        AppendEntries aeproto = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            assertNotNull("Installsnapshot should get called for sending the next chunk of snapshot",
-                isproto);
+        AppendEntries ae = (AppendEntries) SerializationUtils.fromSerializable(aeproto);
 
-            InstallSnapshot is = (InstallSnapshot) SerializationUtils.fromSerializable(isproto);
+        assertTrue("AppendEntries should be sent with empty entries", ae.getEntries().isEmpty());
 
-            assertEquals(snapshotIndex, is.getLastIncludedIndex());
+        //InstallSnapshotReply received
+        fts.markSendStatus(true);
 
-        }};
+        leader.handleMessage(leaderActor, new SendHeartBeat());
+
+        InstallSnapshotMessages.InstallSnapshot isproto = MessageCollectorActor.expectFirstMatching(followerActor,
+                InstallSnapshot.SERIALIZABLE_CLASS);
+
+        InstallSnapshot is = (InstallSnapshot) SerializationUtils.fromSerializable(isproto);
+
+        assertEquals(snapshotIndex, is.getLastIncludedIndex());
     }
 
     @Test
-    public void testSendAppendEntriesSnapshotScenario() {
-        new JavaTestKit(getSystem()) {{
-
-            ActorRef followerActor = getTestActor();
+    public void testSendAppendEntriesSnapshotScenario() throws Exception {
+        logStart("testSendAppendEntriesSnapshotScenario");
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put(followerActor.path().toString(),
-                followerActor.path().toString());
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            MockRaftActorContext actorContext =
-                (MockRaftActorContext) createActorContext(getRef());
-            actorContext.setPeerAddresses(peerAddresses);
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
+        //clears leaders log
+        actorContext.getReplicatedLog().removeFrom(0);
 
-            //clears leaders log
-            actorContext.getReplicatedLog().removeFrom(0);
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int newEntryIndex = 4;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int newEntryIndex = 4;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.setCommitIndex(followersLastIndex);
 
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.setCommitIndex(followersLastIndex);
+        leader = new Leader(actorContext);
 
-            Leader leader = new Leader(actorContext);
+        // Leader will send an immediate heartbeat - ignore it.
+        MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            // new entry
-            ReplicatedLogImplEntry entry =
+        // new entry
+        ReplicatedLogImplEntry entry =
                 new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
-                    new MockRaftActorContext.MockPayload("D"));
+                        new MockRaftActorContext.MockPayload("D"));
 
-            //update follower timestamp
-            leader.markFollowerActive(followerActor.path().toString());
+        //update follower timestamp
+        leader.markFollowerActive(FOLLOWER_ID);
 
-            Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(),
-                TimeUnit.MILLISECONDS);
+        // this should invoke a sendinstallsnapshot as followersLastIndex < snapshotIndex
+        RaftActorBehavior raftBehavior = leader.handleMessage(
+                leaderActor, new Replicate(null, "state-id", entry));
 
-            // this should invoke a sendinstallsnapshot as followersLastIndex < snapshotIndex
-            RaftActorBehavior raftBehavior = leader.handleMessage(
-                senderActor, new Replicate(null, "state-id", entry));
-
-            assertTrue(raftBehavior instanceof Leader);
-
-            // we might receive some heartbeat messages, so wait till we get CaptureSnapshot
-            Boolean[] matches = new ReceiveWhile<Boolean>(Boolean.class, duration("2 seconds")) {
-                @Override
-                protected Boolean match(Object o) throws Exception {
-                    if (o instanceof CaptureSnapshot) {
-                        return true;
-                    }
-                    return false;
-                }
-            }.get();
-
-            boolean captureSnapshot = false;
-            for (Boolean b: matches) {
-                captureSnapshot = b | captureSnapshot;
-            }
+        assertTrue(raftBehavior instanceof Leader);
 
-            assertTrue(captureSnapshot);
-        }};
+        MessageCollectorActor.expectFirstMatching(leaderActor, CaptureSnapshot.class);
     }
 
     @Test
     public void testInitiateInstallSnapshot() throws Exception {
-        new JavaTestKit(getSystem()) {{
-
-            ActorRef leaderActor = getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        logStart("testInitiateInstallSnapshot");
 
-            ActorRef followerActor = getTestActor();
-
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put(followerActor.path().toString(), followerActor.path().toString());
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            MockRaftActorContext actorContext = (MockRaftActorContext) createActorContext(leaderActor);
-            actorContext.setPeerAddresses(peerAddresses);
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
+        //clears leaders log
+        actorContext.getReplicatedLog().removeFrom(0);
 
-            //clears leaders log
-            actorContext.getReplicatedLog().removeFrom(0);
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int newEntryIndex = 4;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int newEntryIndex = 4;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.setLastApplied(3);
+        actorContext.setCommitIndex(followersLastIndex);
 
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.setLastApplied(3);
-            actorContext.setCommitIndex(followersLastIndex);
+        leader = new Leader(actorContext);
 
-            Leader leader = new Leader(actorContext);
-            // set the snapshot as absent and check if capture-snapshot is invoked.
-            leader.setSnapshot(Optional.<ByteString>absent());
+        // Leader will send an immediate heartbeat - ignore it.
+        MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            // new entry
-            ReplicatedLogImplEntry entry = new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
-                    new MockRaftActorContext.MockPayload("D"));
+        // set the snapshot as absent and check if capture-snapshot is invoked.
+        leader.setSnapshot(Optional.<ByteString>absent());
 
-            actorContext.getReplicatedLog().append(entry);
+        // new entry
+        ReplicatedLogImplEntry entry = new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
+                new MockRaftActorContext.MockPayload("D"));
 
-            //update follower timestamp
-            leader.markFollowerActive(followerActor.path().toString());
+        actorContext.getReplicatedLog().append(entry);
 
-            RaftActorBehavior raftBehavior = leader.handleMessage(
-                    senderActor, new Replicate(null, "state-id", entry));
+        //update follower timestamp
+        leader.markFollowerActive(FOLLOWER_ID);
 
-            CaptureSnapshot cs = MessageCollectorActor.
-                getFirstMatching(leaderActor, CaptureSnapshot.class);
+        leader.handleMessage(leaderActor, new Replicate(null, "state-id", entry));
 
-            assertNotNull(cs);
+        CaptureSnapshot cs = MessageCollectorActor.expectFirstMatching(leaderActor, CaptureSnapshot.class);
 
-            assertTrue(cs.isInstallSnapshotInitiated());
-            assertEquals(3, cs.getLastAppliedIndex());
-            assertEquals(1, cs.getLastAppliedTerm());
-            assertEquals(4, cs.getLastIndex());
-            assertEquals(2, cs.getLastTerm());
+        assertTrue(cs.isInstallSnapshotInitiated());
+        assertEquals(3, cs.getLastAppliedIndex());
+        assertEquals(1, cs.getLastAppliedTerm());
+        assertEquals(4, cs.getLastIndex());
+        assertEquals(2, cs.getLastTerm());
 
-            // if an initiate is started again when first is in progress, it shouldnt initiate Capture
-            leader.handleMessage(senderActor, new Replicate(null, "state-id", entry));
-            List<Object> captureSnapshots = MessageCollectorActor.getAllMatching(leaderActor, CaptureSnapshot.class);
-            assertEquals("CaptureSnapshot should not get invoked when  initiate is in progress", 1, captureSnapshots.size());
+        // if an initiate is started again when first is in progress, it shouldnt initiate Capture
+        leader.handleMessage(leaderActor, new Replicate(null, "state-id", entry));
 
-        }};
+        List<CaptureSnapshot> captureSnapshots = MessageCollectorActor.getAllMatching(leaderActor, CaptureSnapshot.class);
+        assertEquals("CaptureSnapshot should not get invoked when  initiate is in progress", 1, captureSnapshots.size());
     }
 
     @Test
-    public void testInstallSnapshot() {
-        new JavaTestKit(getSystem()) {{
+    public void testInstallSnapshot() throws Exception {
+        logStart("testInstallSnapshot");
 
-            ActorRef followerActor = getTestActor();
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put(followerActor.path().toString(),
-                followerActor.path().toString());
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            MockRaftActorContext actorContext =
-                (MockRaftActorContext) createActorContext();
-            actorContext.setPeerAddresses(peerAddresses);
+        //clears leaders log
+        actorContext.getReplicatedLog().removeFrom(0);
 
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
+        actorContext.setCommitIndex(followersLastIndex);
 
-            //clears leaders log
-            actorContext.getReplicatedLog().removeFrom(0);
+        leader = new Leader(actorContext);
 
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int newEntryIndex = 4;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
+        // Ignore initial heartbeat.
+        MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
-            actorContext.setCommitIndex(followersLastIndex);
+        RaftActorBehavior raftBehavior = leader.handleMessage(leaderActor,
+                new SendInstallSnapshot(toByteString(leadersSnapshot)));
 
-            Leader leader = new Leader(actorContext);
+        assertTrue(raftBehavior instanceof Leader);
 
-            // Ignore initial heartbeat.
-            expectMsgClass(duration("5 seconds"), AppendEntries.class);
+        // check if installsnapshot gets called with the correct values.
 
-            // new entry
-            ReplicatedLogImplEntry entry =
-                new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
-                    new MockRaftActorContext.MockPayload("D"));
+        InstallSnapshot installSnapshot = (InstallSnapshot) SerializationUtils.fromSerializable(
+                MessageCollectorActor.expectFirstMatching(followerActor, InstallSnapshotMessages.InstallSnapshot.class));
 
-            RaftActorBehavior raftBehavior = leader.handleMessage(senderActor,
-                new SendInstallSnapshot(toByteString(leadersSnapshot)));
+        assertNotNull(installSnapshot.getData());
+        assertEquals(snapshotIndex, installSnapshot.getLastIncludedIndex());
+        assertEquals(snapshotTerm, installSnapshot.getLastIncludedTerm());
 
-            assertTrue(raftBehavior instanceof Leader);
-
-            // check if installsnapshot gets called with the correct values.
-            final String out =
-                new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                    // do not put code outside this method, will run afterwards
-                    @Override
-                    protected String match(Object in) {
-                        if (in instanceof InstallSnapshotMessages.InstallSnapshot) {
-                            InstallSnapshot is = (InstallSnapshot)
-                                SerializationUtils.fromSerializable(in);
-                            if (is.getData() == null) {
-                                return "InstallSnapshot data is null";
-                            }
-                            if (is.getLastIncludedIndex() != snapshotIndex) {
-                                return is.getLastIncludedIndex() + "!=" + snapshotIndex;
-                            }
-                            if (is.getLastIncludedTerm() != snapshotTerm) {
-                                return is.getLastIncludedTerm() + "!=" + snapshotTerm;
-                            }
-                            if (is.getTerm() == currentTerm) {
-                                return is.getTerm() + "!=" + currentTerm;
-                            }
-
-                            return "match";
-
-                        } else {
-                            return "message mismatch:" + in.getClass();
-                        }
-                    }
-                }.get(); // this extracts the received message
-
-            assertEquals("match", out);
-        }};
+        assertEquals(currentTerm, installSnapshot.getTerm());
     }
 
     @Test
-    public void testHandleInstallSnapshotReplyLastChunk() {
-        new JavaTestKit(getSystem()) {{
+    public void testHandleInstallSnapshotReplyLastChunk() throws Exception {
+        logStart("testHandleInstallSnapshotReplyLastChunk");
 
-            ActorRef followerActor = getTestActor();
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put(followerActor.path().toString(),
-                followerActor.path().toString());
-
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int newEntryIndex = 4;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
-
-            MockRaftActorContext actorContext =
-                (MockRaftActorContext) createActorContext();
-            actorContext.setPeerAddresses(peerAddresses);
-            actorContext.setCommitIndex(followersLastIndex);
-
-            MockLeader leader = new MockLeader(actorContext);
-
-            // Ignore initial heartbeat.
-            expectMsgClass(duration("5 seconds"), AppendEntries.class);
-
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
-
-            // set the snapshot variables in replicatedlog
-
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
-
-            ByteString bs = toByteString(leadersSnapshot);
-            leader.setSnapshot(Optional.of(bs));
-            leader.createFollowerToSnapshot(followerActor.path().toString(), bs);
-            while(!leader.getFollowerToSnapshot().isLastChunk(leader.getFollowerToSnapshot().getChunkIndex())) {
-                leader.getFollowerToSnapshot().getNextChunk();
-                leader.getFollowerToSnapshot().incrementChunkIndex();
-            }
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            //clears leaders log
-            actorContext.getReplicatedLog().removeFrom(0);
+        actorContext.setCommitIndex(followersLastIndex);
 
-            RaftActorBehavior raftBehavior = leader.handleMessage(senderActor,
-                new InstallSnapshotReply(currentTerm, followerActor.path().toString(),
-                    leader.getFollowerToSnapshot().getChunkIndex(), true));
+        leader = new Leader(actorContext);
 
-            assertTrue(raftBehavior instanceof Leader);
+        // Ignore initial heartbeat.
+        MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            assertEquals(0, leader.followerSnapshotSize());
-            assertEquals(1, leader.followerLogSize());
-            assertNotNull(leader.getFollower(followerActor.path().toString()));
-            FollowerLogInformation fli = leader.getFollower(followerActor.path().toString());
-            assertEquals(snapshotIndex, fli.getMatchIndex());
-            assertEquals(snapshotIndex, fli.getMatchIndex());
-            assertEquals(snapshotIndex + 1, fli.getNextIndex());
-        }};
-    }
-    @Test
-    public void testSendSnapshotfromInstallSnapshotReply() throws Exception {
-        new JavaTestKit(getSystem()) {{
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            TestActorRef<MessageCollectorActor> followerActor =
-                TestActorRef.create(getSystem(), Props.create(MessageCollectorActor.class), "follower-reply");
+        // set the snapshot variables in replicatedlog
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower-reply",
-                followerActor.path().toString());
-
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
-
-            MockRaftActorContext actorContext =
-                (MockRaftActorContext) createActorContext();
-            DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl(){
-                @Override
-                public int getSnapshotChunkSize() {
-                    return 50;
-                }
-            };
-            configParams.setHeartBeatInterval(new FiniteDuration(9, TimeUnit.SECONDS));
-            configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
 
-            actorContext.setConfigParams(configParams);
-            actorContext.setPeerAddresses(peerAddresses);
-            actorContext.setCommitIndex(followersLastIndex);
+        ByteString bs = toByteString(leadersSnapshot);
+        leader.setSnapshot(Optional.of(bs));
+        FollowerToSnapshot fts = leader.new FollowerToSnapshot(bs);
+        leader.setFollowerSnapshot(FOLLOWER_ID, fts);
+        while(!fts.isLastChunk(fts.getChunkIndex())) {
+            fts.getNextChunk();
+            fts.incrementChunkIndex();
+        }
 
-            MockLeader leader = new MockLeader(actorContext);
+        //clears leaders log
+        actorContext.getReplicatedLog().removeFrom(0);
 
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
+        RaftActorBehavior raftBehavior = leader.handleMessage(followerActor,
+                new InstallSnapshotReply(currentTerm, FOLLOWER_ID, fts.getChunkIndex(), true));
 
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
+        assertTrue(raftBehavior instanceof Leader);
 
-            ByteString bs = toByteString(leadersSnapshot);
-            leader.setSnapshot(Optional.of(bs));
+        assertEquals(0, leader.followerSnapshotSize());
+        assertEquals(1, leader.followerLogSize());
+        FollowerLogInformation fli = leader.getFollower(FOLLOWER_ID);
+        assertNotNull(fli);
+        assertEquals(snapshotIndex, fli.getMatchIndex());
+        assertEquals(snapshotIndex, fli.getMatchIndex());
+        assertEquals(snapshotIndex + 1, fli.getNextIndex());
+    }
 
-            leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
+    @Test
+    public void testSendSnapshotfromInstallSnapshotReply() throws Exception {
+        logStart("testSendSnapshotfromInstallSnapshotReply");
 
-            List<Object> objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            assertEquals(1, objectList.size());
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            Object o = objectList.get(0);
-            assertTrue(o instanceof InstallSnapshotMessages.InstallSnapshot);
+        DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl(){
+            @Override
+            public int getSnapshotChunkSize() {
+                return 50;
+            }
+        };
+        configParams.setHeartBeatInterval(new FiniteDuration(9, TimeUnit.SECONDS));
+        configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
 
-            InstallSnapshotMessages.InstallSnapshot installSnapshot = (InstallSnapshotMessages.InstallSnapshot) o;
+        actorContext.setConfigParams(configParams);
+        actorContext.setCommitIndex(followersLastIndex);
 
-            assertEquals(1, installSnapshot.getChunkIndex());
-            assertEquals(3, installSnapshot.getTotalChunks());
+        leader = new Leader(actorContext);
 
-            leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
-                "follower-reply", installSnapshot.getChunkIndex(), true));
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
 
-            assertEquals(2, objectList.size());
+        ByteString bs = toByteString(leadersSnapshot);
+        leader.setSnapshot(Optional.of(bs));
 
-            installSnapshot = (InstallSnapshotMessages.InstallSnapshot) objectList.get(1);
+        leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
 
-            leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
-                "follower-reply", installSnapshot.getChunkIndex(), true));
+        InstallSnapshotMessages.InstallSnapshot installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-            objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        assertEquals(1, installSnapshot.getChunkIndex());
+        assertEquals(3, installSnapshot.getTotalChunks());
 
-            assertEquals(3, objectList.size());
+        followerActor.underlyingActor().clear();
+        leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
+                FOLLOWER_ID, installSnapshot.getChunkIndex(), true));
 
-            installSnapshot = (InstallSnapshotMessages.InstallSnapshot) objectList.get(2);
+        installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-            // Send snapshot reply one more time and make sure that a new snapshot message should not be sent to follower
-            leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
-                "follower-reply", installSnapshot.getChunkIndex(), true));
+        assertEquals(2, installSnapshot.getChunkIndex());
+        assertEquals(3, installSnapshot.getTotalChunks());
 
-            objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        followerActor.underlyingActor().clear();
+        leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
+                FOLLOWER_ID, installSnapshot.getChunkIndex(), true));
 
-            // Count should still stay at 3
-            assertEquals(3, objectList.size());
-        }};
+        installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
+
+        // Send snapshot reply one more time and make sure that a new snapshot message should not be sent to follower
+        followerActor.underlyingActor().clear();
+        leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
+                FOLLOWER_ID, installSnapshot.getChunkIndex(), true));
+
+        installSnapshot = MessageCollectorActor.getFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
+
+        Assert.assertNull(installSnapshot);
     }
 
 
     @Test
     public void testHandleInstallSnapshotReplyWithInvalidChunkIndex() throws Exception{
-        new JavaTestKit(getSystem()) {{
-
-            TestActorRef<MessageCollectorActor> followerActor =
-                    TestActorRef.create(getSystem(), Props.create(MessageCollectorActor.class), "follower");
-
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put(followerActor.path().toString(),
-                    followerActor.path().toString());
+        logStart("testHandleInstallSnapshotReplyWithInvalidChunkIndex");
 
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            MockRaftActorContext actorContext =
-                    (MockRaftActorContext) createActorContext();
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            actorContext.setConfigParams(new DefaultConfigParamsImpl(){
-                @Override
-                public int getSnapshotChunkSize() {
-                    return 50;
-                }
-            });
-            actorContext.setPeerAddresses(peerAddresses);
-            actorContext.setCommitIndex(followersLastIndex);
+        actorContext.setConfigParams(new DefaultConfigParamsImpl(){
+            @Override
+            public int getSnapshotChunkSize() {
+                return 50;
+            }
+        });
 
-            MockLeader leader = new MockLeader(actorContext);
+        actorContext.setCommitIndex(followersLastIndex);
 
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
+        leader = new Leader(actorContext);
 
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            ByteString bs = toByteString(leadersSnapshot);
-            leader.setSnapshot(Optional.of(bs));
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
 
-            leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
+        ByteString bs = toByteString(leadersSnapshot);
+        leader.setSnapshot(Optional.of(bs));
 
-            MessageCollectorActor.getAllMatching(followerActor,
-                    InstallSnapshotMessages.InstallSnapshot.class);
+        leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
 
-            InstallSnapshotMessages.InstallSnapshot installSnapshot = MessageCollectorActor.getFirstMatching(
-                    followerActor, InstallSnapshotMessages.InstallSnapshot.class);
-            assertNotNull(installSnapshot);
+        InstallSnapshotMessages.InstallSnapshot installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-            assertEquals(1, installSnapshot.getChunkIndex());
-            assertEquals(3, installSnapshot.getTotalChunks());
+        assertEquals(1, installSnapshot.getChunkIndex());
+        assertEquals(3, installSnapshot.getTotalChunks());
 
-            followerActor.underlyingActor().clear();
+        followerActor.underlyingActor().clear();
 
-            leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
-                followerActor.path().toString(), -1, false));
+        leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
+                FOLLOWER_ID, -1, false));
 
-            Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(),
+        Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(),
                 TimeUnit.MILLISECONDS);
 
-            leader.handleMessage(leaderActor, new SendHeartBeat());
-
-            installSnapshot = MessageCollectorActor.getFirstMatching(
-                    followerActor, InstallSnapshotMessages.InstallSnapshot.class);
-            assertNotNull(installSnapshot);
+        leader.handleMessage(leaderActor, new SendHeartBeat());
 
-            assertEquals(1, installSnapshot.getChunkIndex());
-            assertEquals(3, installSnapshot.getTotalChunks());
+        installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-            followerActor.tell(PoisonPill.getInstance(), getRef());
-        }};
+        assertEquals(1, installSnapshot.getChunkIndex());
+        assertEquals(3, installSnapshot.getTotalChunks());
     }
 
     @Test
     public void testHandleSnapshotSendsPreviousChunksHashCodeWhenSendingNextChunk() throws Exception {
-        new JavaTestKit(getSystem()) {
-            {
-                TestActorRef<MessageCollectorActor> followerActor =
-                        TestActorRef.create(getSystem(), Props.create(MessageCollectorActor.class), "follower-chunk");
-
-                Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put(followerActor.path().toString(),
-                        followerActor.path().toString());
+        logStart("testHandleSnapshotSendsPreviousChunksHashCodeWhenSendingNextChunk");
 
-                final int followersLastIndex = 2;
-                final int snapshotIndex = 3;
-                final int snapshotTerm = 1;
-                final int currentTerm = 2;
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-                MockRaftActorContext actorContext =
-                        (MockRaftActorContext) createActorContext();
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-                actorContext.setConfigParams(new DefaultConfigParamsImpl() {
-                    @Override
-                    public int getSnapshotChunkSize() {
-                        return 50;
-                    }
-                });
-                actorContext.setPeerAddresses(peerAddresses);
-                actorContext.setCommitIndex(followersLastIndex);
+        actorContext.setConfigParams(new DefaultConfigParamsImpl() {
+            @Override
+            public int getSnapshotChunkSize() {
+                return 50;
+            }
+        });
 
-                MockLeader leader = new MockLeader(actorContext);
+        actorContext.setCommitIndex(followersLastIndex);
 
-                Map<String, String> leadersSnapshot = new HashMap<>();
-                leadersSnapshot.put("1", "A");
-                leadersSnapshot.put("2", "B");
-                leadersSnapshot.put("3", "C");
+        leader = new Leader(actorContext);
 
-                // set the snapshot variables in replicatedlog
-                actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-                actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-                actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-                ByteString bs = toByteString(leadersSnapshot);
-                leader.setSnapshot(Optional.of(bs));
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
 
-                leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
+        ByteString bs = toByteString(leadersSnapshot);
+        leader.setSnapshot(Optional.of(bs));
 
-                InstallSnapshotMessages.InstallSnapshot installSnapshot = MessageCollectorActor.getFirstMatching(
-                        followerActor, InstallSnapshotMessages.InstallSnapshot.class);
-                assertNotNull(installSnapshot);
+        leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
 
-                assertEquals(1, installSnapshot.getChunkIndex());
-                assertEquals(3, installSnapshot.getTotalChunks());
-                assertEquals(AbstractLeader.INITIAL_LAST_CHUNK_HASH_CODE, installSnapshot.getLastChunkHashCode());
+        InstallSnapshotMessages.InstallSnapshot installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-                int hashCode = installSnapshot.getData().hashCode();
+        assertEquals(1, installSnapshot.getChunkIndex());
+        assertEquals(3, installSnapshot.getTotalChunks());
+        assertEquals(AbstractLeader.INITIAL_LAST_CHUNK_HASH_CODE, installSnapshot.getLastChunkHashCode());
 
-                followerActor.underlyingActor().clear();
+        int hashCode = installSnapshot.getData().hashCode();
 
-                leader.handleMessage(followerActor, new InstallSnapshotReply(installSnapshot.getTerm(),followerActor.path().toString(),1,true ));
+        followerActor.underlyingActor().clear();
 
-                installSnapshot = MessageCollectorActor.getFirstMatching(
-                        followerActor, InstallSnapshotMessages.InstallSnapshot.class);
-                assertNotNull(installSnapshot);
+        leader.handleMessage(followerActor, new InstallSnapshotReply(installSnapshot.getTerm(),
+                FOLLOWER_ID, 1, true));
 
-                assertEquals(2, installSnapshot.getChunkIndex());
-                assertEquals(3, installSnapshot.getTotalChunks());
-                assertEquals(hashCode, installSnapshot.getLastChunkHashCode());
+        installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-                followerActor.tell(PoisonPill.getInstance(), getRef());
-            }};
+        assertEquals(2, installSnapshot.getChunkIndex());
+        assertEquals(3, installSnapshot.getTotalChunks());
+        assertEquals(hashCode, installSnapshot.getLastChunkHashCode());
     }
 
     @Test
     public void testFollowerToSnapshotLogic() {
+        logStart("testFollowerToSnapshotLogic");
 
-        MockRaftActorContext actorContext = (MockRaftActorContext) createActorContext();
+        MockRaftActorContext actorContext = createActorContext();
 
         actorContext.setConfigParams(new DefaultConfigParamsImpl() {
             @Override
@@ -847,7 +689,7 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
             }
         });
 
-        MockLeader leader = new MockLeader(actorContext);
+        leader = new Leader(actorContext);
 
         Map<String, String> leadersSnapshot = new HashMap<>();
         leadersSnapshot.put("1", "A");
@@ -857,7 +699,9 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
         ByteString bs = toByteString(leadersSnapshot);
         byte[] barray = bs.toByteArray();
 
-        leader.createFollowerToSnapshot("followerId", bs);
+        FollowerToSnapshot fts = leader.new FollowerToSnapshot(bs);
+        leader.setFollowerSnapshot(FOLLOWER_ID, fts);
+
         assertEquals(bs.size(), barray.length);
 
         int chunkIndex=0;
@@ -869,386 +713,294 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                 j = barray.length;
             }
 
-            ByteString chunk = leader.getFollowerToSnapshot().getNextChunk();
+            ByteString chunk = fts.getNextChunk();
             assertEquals("bytestring size not matching for chunk:"+ chunkIndex, j-i, chunk.size());
-            assertEquals("chunkindex not matching", chunkIndex, leader.getFollowerToSnapshot().getChunkIndex());
+            assertEquals("chunkindex not matching", chunkIndex, fts.getChunkIndex());
 
-            leader.getFollowerToSnapshot().markSendStatus(true);
-            if (!leader.getFollowerToSnapshot().isLastChunk(chunkIndex)) {
-                leader.getFollowerToSnapshot().incrementChunkIndex();
+            fts.markSendStatus(true);
+            if (!fts.isLastChunk(chunkIndex)) {
+                fts.incrementChunkIndex();
             }
         }
 
-        assertEquals("totalChunks not matching", chunkIndex, leader.getFollowerToSnapshot().getTotalChunks());
+        assertEquals("totalChunks not matching", chunkIndex, fts.getTotalChunks());
     }
 
-
     @Override protected RaftActorBehavior createBehavior(
         RaftActorContext actorContext) {
         return new Leader(actorContext);
     }
 
-    @Override protected RaftActorContext createActorContext() {
+    @Override
+    protected MockRaftActorContext createActorContext() {
         return createActorContext(leaderActor);
     }
 
     @Override
-    protected RaftActorContext createActorContext(ActorRef actorRef) {
+    protected MockRaftActorContext createActorContext(ActorRef actorRef) {
+        return createActorContext("leader", actorRef);
+    }
+
+    private MockRaftActorContext createActorContextWithFollower() {
+        MockRaftActorContext actorContext = createActorContext();
+        actorContext.setPeerAddresses(ImmutableMap.<String, String>builder().put(FOLLOWER_ID,
+                followerActor.path().toString()).build());
+        return actorContext;
+    }
+
+    private MockRaftActorContext createActorContext(String id, ActorRef actorRef) {
         DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
         configParams.setHeartBeatInterval(new FiniteDuration(50, TimeUnit.MILLISECONDS));
         configParams.setElectionTimeoutFactor(100000);
-        MockRaftActorContext context = new MockRaftActorContext("test", getSystem(), actorRef);
+        MockRaftActorContext context = new MockRaftActorContext(id, getSystem(), actorRef);
         context.setConfigParams(configParams);
         return context;
     }
 
-    private ByteString toByteString(Map<String, String> state) {
-        ByteArrayOutputStream b = null;
-        ObjectOutputStream o = null;
-        try {
-            try {
-                b = new ByteArrayOutputStream();
-                o = new ObjectOutputStream(b);
-                o.writeObject(state);
-                byte[] snapshotBytes = b.toByteArray();
-                return ByteString.copyFrom(snapshotBytes);
-            } finally {
-                if (o != null) {
-                    o.flush();
-                    o.close();
-                }
-                if (b != null) {
-                    b.close();
-                }
-            }
-        } catch (IOException e) {
-            Assert.fail("IOException in converting Hashmap to Bytestring:" + e);
-        }
-        return null;
-    }
-
-    public static class ForwardMessageToBehaviorActor extends MessageCollectorActor {
-        AbstractRaftActorBehavior behavior;
-
-        @Override public void onReceive(Object message) throws Exception {
-            if(behavior != null) {
-                behavior.handleMessage(sender(), message);
-            }
-
-            super.onReceive(message);
-        }
-
-        public static Props props() {
-            return Props.create(ForwardMessageToBehaviorActor.class);
-        }
-    }
-
     @Test
     public void testLeaderCreatedWithCommitIndexLessThanLastIndex() throws Exception {
-        new JavaTestKit(getSystem()) {{
-            TestActorRef<ForwardMessageToBehaviorActor> leaderActor = TestActorRef.create(getSystem(),
-                    Props.create(ForwardMessageToBehaviorActor.class));
+        logStart("testLeaderCreatedWithCommitIndexLessThanLastIndex");
 
-            MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        MockRaftActorContext leaderActorContext = createActorContextWithFollower();
 
-            TestActorRef<ForwardMessageToBehaviorActor> followerActor = TestActorRef.create(getSystem(),
-                    ForwardMessageToBehaviorActor.props());
+        MockRaftActorContext followerActorContext = createActorContext(FOLLOWER_ID, followerActor);
 
-            MockRaftActorContext followerActorContext =
-                    new MockRaftActorContext("follower", getSystem(), followerActor);
+        Follower follower = new Follower(followerActorContext);
+        followerActor.underlyingActor().setBehavior(follower);
 
-            Follower follower = new Follower(followerActorContext);
-            followerActor.underlyingActor().behavior = follower;
+        Map<String, String> peerAddresses = new HashMap<>();
+        peerAddresses.put(FOLLOWER_ID, followerActor.path().toString());
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower", followerActor.path().toString());
+        leaderActorContext.setPeerAddresses(peerAddresses);
 
-            leaderActorContext.setPeerAddresses(peerAddresses);
+        leaderActorContext.getReplicatedLog().removeFrom(0);
 
-            leaderActorContext.getReplicatedLog().removeFrom(0);
+        //create 3 entries
+        leaderActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
 
-            //create 3 entries
-            leaderActorContext.setReplicatedLog(
-                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        leaderActorContext.setCommitIndex(1);
 
-            leaderActorContext.setCommitIndex(1);
+        followerActorContext.getReplicatedLog().removeFrom(0);
 
-            followerActorContext.getReplicatedLog().removeFrom(0);
+        // follower too has the exact same log entries and has the same commit index
+        followerActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
 
-            // follower too has the exact same log entries and has the same commit index
-            followerActorContext.setReplicatedLog(
-                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        followerActorContext.setCommitIndex(1);
 
-            followerActorContext.setCommitIndex(1);
+        leader = new Leader(leaderActorContext);
 
-            Leader leader = new Leader(leaderActorContext);
+        AppendEntries appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            AppendEntries appendEntries = MessageCollectorActor.getFirstMatching(followerActor, AppendEntries.class);
-            assertNotNull(appendEntries);
+        assertEquals(1, appendEntries.getLeaderCommit());
+        assertEquals(0, appendEntries.getEntries().size());
+        assertEquals(0, appendEntries.getPrevLogIndex());
 
-            assertEquals(1, appendEntries.getLeaderCommit());
-            assertEquals(0, appendEntries.getEntries().size());
-            assertEquals(0, appendEntries.getPrevLogIndex());
+        AppendEntriesReply appendEntriesReply = MessageCollectorActor.expectFirstMatching(
+                leaderActor, AppendEntriesReply.class);
 
-            AppendEntriesReply appendEntriesReply = MessageCollectorActor.getFirstMatching(
-                    leaderActor, AppendEntriesReply.class);
-            assertNotNull(appendEntriesReply);
+        assertEquals(2, appendEntriesReply.getLogLastIndex());
+        assertEquals(1, appendEntriesReply.getLogLastTerm());
 
-            assertEquals(2, appendEntriesReply.getLogLastIndex());
-            assertEquals(1, appendEntriesReply.getLogLastTerm());
+        // follower returns its next index
+        assertEquals(2, appendEntriesReply.getLogLastIndex());
+        assertEquals(1, appendEntriesReply.getLogLastTerm());
 
-            // follower returns its next index
-            assertEquals(2, appendEntriesReply.getLogLastIndex());
-            assertEquals(1, appendEntriesReply.getLogLastTerm());
-        }};
+        follower.close();
     }
 
-
     @Test
     public void testLeaderCreatedWithCommitIndexLessThanFollowersCommitIndex() throws Exception {
-        new JavaTestKit(getSystem()) {{
-            TestActorRef<ForwardMessageToBehaviorActor> leaderActor = TestActorRef.create(getSystem(),
-                    Props.create(ForwardMessageToBehaviorActor.class));
+        logStart("testLeaderCreatedWithCommitIndexLessThanFollowersCommitIndex");
 
-            MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        MockRaftActorContext leaderActorContext = createActorContext();
 
-            TestActorRef<ForwardMessageToBehaviorActor> followerActor = TestActorRef.create(getSystem(),
-                    ForwardMessageToBehaviorActor.props());
+        MockRaftActorContext followerActorContext = createActorContext(FOLLOWER_ID, followerActor);
 
-            MockRaftActorContext followerActorContext =
-                    new MockRaftActorContext("follower", getSystem(), followerActor);
+        Follower follower = new Follower(followerActorContext);
+        followerActor.underlyingActor().setBehavior(follower);
 
-            Follower follower = new Follower(followerActorContext);
-            followerActor.underlyingActor().behavior = follower;
+        Map<String, String> peerAddresses = new HashMap<>();
+        peerAddresses.put(FOLLOWER_ID, followerActor.path().toString());
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower", followerActor.path().toString());
+        leaderActorContext.setPeerAddresses(peerAddresses);
 
-            leaderActorContext.setPeerAddresses(peerAddresses);
+        leaderActorContext.getReplicatedLog().removeFrom(0);
 
-            leaderActorContext.getReplicatedLog().removeFrom(0);
+        leaderActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
 
-            leaderActorContext.setReplicatedLog(
-                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        leaderActorContext.setCommitIndex(1);
 
-            leaderActorContext.setCommitIndex(1);
+        followerActorContext.getReplicatedLog().removeFrom(0);
 
-            followerActorContext.getReplicatedLog().removeFrom(0);
+        followerActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
 
-            followerActorContext.setReplicatedLog(
-                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        // follower has the same log entries but its commit index > leaders commit index
+        followerActorContext.setCommitIndex(2);
 
-            // follower has the same log entries but its commit index > leaders commit index
-            followerActorContext.setCommitIndex(2);
+        leader = new Leader(leaderActorContext);
 
-            Leader leader = new Leader(leaderActorContext);
+        // Initial heartbeat
+        AppendEntries appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            // Initial heartbeat
-            AppendEntries appendEntries = MessageCollectorActor.getFirstMatching(followerActor, AppendEntries.class);
-            assertNotNull(appendEntries);
+        assertEquals(1, appendEntries.getLeaderCommit());
+        assertEquals(0, appendEntries.getEntries().size());
+        assertEquals(0, appendEntries.getPrevLogIndex());
 
-            assertEquals(1, appendEntries.getLeaderCommit());
-            assertEquals(0, appendEntries.getEntries().size());
-            assertEquals(0, appendEntries.getPrevLogIndex());
+        AppendEntriesReply appendEntriesReply = MessageCollectorActor.expectFirstMatching(
+                leaderActor, AppendEntriesReply.class);
 
-            AppendEntriesReply appendEntriesReply = MessageCollectorActor.getFirstMatching(
-                    leaderActor, AppendEntriesReply.class);
-            assertNotNull(appendEntriesReply);
+        assertEquals(2, appendEntriesReply.getLogLastIndex());
+        assertEquals(1, appendEntriesReply.getLogLastTerm());
 
-            assertEquals(2, appendEntriesReply.getLogLastIndex());
-            assertEquals(1, appendEntriesReply.getLogLastTerm());
+        leaderActor.underlyingActor().setBehavior(follower);
+        leader.handleMessage(followerActor, appendEntriesReply);
 
-            leaderActor.underlyingActor().behavior = leader;
-            leader.handleMessage(followerActor, appendEntriesReply);
+        leaderActor.underlyingActor().clear();
+        followerActor.underlyingActor().clear();
 
-            leaderActor.underlyingActor().clear();
-            followerActor.underlyingActor().clear();
+        Uninterruptibles.sleepUninterruptibly(leaderActorContext.getConfigParams().getHeartBeatInterval().toMillis(),
+                TimeUnit.MILLISECONDS);
 
-            Uninterruptibles.sleepUninterruptibly(leaderActorContext.getConfigParams().getHeartBeatInterval().toMillis(),
-                    TimeUnit.MILLISECONDS);
+        leader.handleMessage(leaderActor, new SendHeartBeat());
 
-            leader.handleMessage(leaderActor, new SendHeartBeat());
+        appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            appendEntries = MessageCollectorActor.getFirstMatching(followerActor, AppendEntries.class);
-            assertNotNull(appendEntries);
+        assertEquals(2, appendEntries.getLeaderCommit());
+        assertEquals(0, appendEntries.getEntries().size());
+        assertEquals(2, appendEntries.getPrevLogIndex());
 
-            assertEquals(1, appendEntries.getLeaderCommit());
-            assertEquals(0, appendEntries.getEntries().size());
-            assertEquals(2, appendEntries.getPrevLogIndex());
+        appendEntriesReply = MessageCollectorActor.expectFirstMatching(leaderActor, AppendEntriesReply.class);
 
-            appendEntriesReply = MessageCollectorActor.getFirstMatching(leaderActor, AppendEntriesReply.class);
-            assertNotNull(appendEntriesReply);
+        assertEquals(2, appendEntriesReply.getLogLastIndex());
+        assertEquals(1, appendEntriesReply.getLogLastTerm());
 
-            assertEquals(2, appendEntriesReply.getLogLastIndex());
-            assertEquals(1, appendEntriesReply.getLogLastTerm());
+        assertEquals(2, followerActorContext.getCommitIndex());
 
-            assertEquals(1, followerActorContext.getCommitIndex());
-        }};
+        follower.close();
     }
 
     @Test
     public void testHandleAppendEntriesReplyFailure(){
-        new JavaTestKit(getSystem()) {
-            {
-
-                ActorRef leaderActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        logStart("testHandleAppendEntriesReplyFailure");
 
-                ActorRef followerActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        MockRaftActorContext leaderActorContext = createActorContextWithFollower();
 
+        leader = new Leader(leaderActorContext);
 
-                MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        // Send initial heartbeat reply with last index.
+        leader.handleAppendEntriesReply(followerActor, new AppendEntriesReply(FOLLOWER_ID, 1, true, 10, 1));
 
-                Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put("follower-1",
-                    followerActor.path().toString());
+        FollowerLogInformation followerInfo = leader.getFollower(FOLLOWER_ID);
+        assertEquals("getNextIndex", 11, followerInfo.getNextIndex());
 
-                leaderActorContext.setPeerAddresses(peerAddresses);
+        AppendEntriesReply reply = new AppendEntriesReply(FOLLOWER_ID, 1, false, 10, 1);
 
-                Leader leader = new Leader(leaderActorContext);
+        RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
 
-                AppendEntriesReply reply = new AppendEntriesReply("follower-1", 1, false, 10, 1);
+        assertEquals(RaftState.Leader, raftActorBehavior.state());
 
-                RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
-
-                assertEquals(RaftState.Leader, raftActorBehavior.state());
-
-            }};
+        assertEquals("getNextIndex", 10, followerInfo.getNextIndex());
     }
 
     @Test
     public void testHandleAppendEntriesReplySuccess() throws Exception {
-        new JavaTestKit(getSystem()) {
-            {
-
-                ActorRef leaderActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        logStart("testHandleAppendEntriesReplySuccess");
 
-                ActorRef followerActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        MockRaftActorContext leaderActorContext = createActorContextWithFollower();
 
+        leaderActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
 
-                MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        leaderActorContext.setCommitIndex(1);
+        leaderActorContext.setLastApplied(1);
+        leaderActorContext.getTermInformation().update(1, "leader");
 
-                leaderActorContext.setReplicatedLog(
-                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        leader = new Leader(leaderActorContext);
 
-                Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put("follower-1",
-                    followerActor.path().toString());
+        AppendEntriesReply reply = new AppendEntriesReply(FOLLOWER_ID, 1, true, 2, 1);
 
-                leaderActorContext.setPeerAddresses(peerAddresses);
-                leaderActorContext.setCommitIndex(1);
-                leaderActorContext.setLastApplied(1);
-                leaderActorContext.getTermInformation().update(1, "leader");
+        RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
 
-                Leader leader = new Leader(leaderActorContext);
+        assertEquals(RaftState.Leader, raftActorBehavior.state());
 
-                AppendEntriesReply reply = new AppendEntriesReply("follower-1", 1, true, 2, 1);
+        assertEquals(2, leaderActorContext.getCommitIndex());
 
-                RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
+        ApplyLogEntries applyLogEntries = MessageCollectorActor.expectFirstMatching(
+                leaderActor, ApplyLogEntries.class);
 
-                assertEquals(RaftState.Leader, raftActorBehavior.state());
+        assertEquals(2, leaderActorContext.getLastApplied());
 
-                assertEquals(2, leaderActorContext.getCommitIndex());
+        assertEquals(2, applyLogEntries.getToIndex());
 
-                ApplyLogEntries applyLogEntries =
-                    MessageCollectorActor.getFirstMatching(leaderActor,
-                    ApplyLogEntries.class);
+        List<ApplyState> applyStateList = MessageCollectorActor.getAllMatching(leaderActor,
+                ApplyState.class);
 
-                assertNotNull(applyLogEntries);
+        assertEquals(1,applyStateList.size());
 
-                assertEquals(2, leaderActorContext.getLastApplied());
+        ApplyState applyState = applyStateList.get(0);
 
-                assertEquals(2, applyLogEntries.getToIndex());
-
-                List<Object> applyStateList = MessageCollectorActor.getAllMatching(leaderActor,
-                    ApplyState.class);
-
-                assertEquals(1,applyStateList.size());
-
-                ApplyState applyState = (ApplyState) applyStateList.get(0);
-
-                assertEquals(2, applyState.getReplicatedLogEntry().getIndex());
-
-            }};
+        assertEquals(2, applyState.getReplicatedLogEntry().getIndex());
     }
 
     @Test
     public void testHandleAppendEntriesReplyUnknownFollower(){
-        new JavaTestKit(getSystem()) {
-            {
-
-                ActorRef leaderActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        logStart("testHandleAppendEntriesReplyUnknownFollower");
 
-                MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        MockRaftActorContext leaderActorContext = createActorContext();
 
-                Leader leader = new Leader(leaderActorContext);
+        leader = new Leader(leaderActorContext);
 
-                AppendEntriesReply reply = new AppendEntriesReply("follower-1", 1, false, 10, 1);
+        AppendEntriesReply reply = new AppendEntriesReply("unkown-follower", 1, false, 10, 1);
 
-                RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(getRef(), reply);
+        RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
 
-                assertEquals(RaftState.Leader, raftActorBehavior.state());
-
-            }};
+        assertEquals(RaftState.Leader, raftActorBehavior.state());
     }
 
     @Test
     public void testHandleRequestVoteReply(){
-        new JavaTestKit(getSystem()) {
-            {
-
-                ActorRef leaderActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        logStart("testHandleRequestVoteReply");
 
-                MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        MockRaftActorContext leaderActorContext = createActorContext();
 
-                Leader leader = new Leader(leaderActorContext);
+        leader = new Leader(leaderActorContext);
 
-                RaftActorBehavior raftActorBehavior = leader.handleRequestVoteReply(getRef(), new RequestVoteReply(1, true));
+        // Should be a no-op.
+        RaftActorBehavior raftActorBehavior = leader.handleRequestVoteReply(followerActor,
+                new RequestVoteReply(1, true));
 
-                assertEquals(RaftState.Leader, raftActorBehavior.state());
+        assertEquals(RaftState.Leader, raftActorBehavior.state());
 
-                raftActorBehavior = leader.handleRequestVoteReply(getRef(), new RequestVoteReply(1, false));
+        raftActorBehavior = leader.handleRequestVoteReply(followerActor, new RequestVoteReply(1, false));
 
-                assertEquals(RaftState.Leader, raftActorBehavior.state());
-            }};
+        assertEquals(RaftState.Leader, raftActorBehavior.state());
     }
 
     @Test
     public void testIsolatedLeaderCheckNoFollowers() {
-        new JavaTestKit(getSystem()) {{
-            ActorRef leaderActor = getTestActor();
+        logStart("testIsolatedLeaderCheckNoFollowers");
 
-            MockRaftActorContext leaderActorContext =
-                new MockRaftActorContext("leader", getSystem(), leaderActor);
+        MockRaftActorContext leaderActorContext = createActorContext();
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            leaderActorContext.setPeerAddresses(peerAddresses);
-
-            Leader leader = new Leader(leaderActorContext);
-            RaftActorBehavior behavior = leader.handleMessage(leaderActor, new IsolatedLeaderCheck());
-            Assert.assertTrue(behavior instanceof Leader);
-        }};
+        leader = new Leader(leaderActorContext);
+        RaftActorBehavior behavior = leader.handleMessage(leaderActor, new IsolatedLeaderCheck());
+        Assert.assertTrue(behavior instanceof Leader);
     }
 
     @Test
     public void testIsolatedLeaderCheckTwoFollowers() throws Exception {
+        logStart("testIsolatedLeaderCheckTwoFollowers");
+
         new JavaTestKit(getSystem()) {{
 
             ActorRef followerActor1 = getTestActor();
             ActorRef followerActor2 = getTestActor();
 
-            MockRaftActorContext leaderActorContext = (MockRaftActorContext) createActorContext();
+            MockRaftActorContext leaderActorContext = createActorContext();
 
             Map<String, String> peerAddresses = new HashMap<>();
             peerAddresses.put("follower-1", followerActor1.path().toString());
@@ -1256,8 +1008,7 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
 
             leaderActorContext.setPeerAddresses(peerAddresses);
 
-            Leader leader = new Leader(leaderActorContext);
-            leader.stopIsolatedLeaderCheckSchedule();
+            leader = new Leader(leaderActorContext);
 
             leader.markFollowerActive("follower-1");
             leader.markFollowerActive("follower-2");
@@ -1289,118 +1040,150 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
             behavior = leader.handleMessage(leaderActor, new IsolatedLeaderCheck());
             Assert.assertTrue("Behavior not instance of IsolatedLeader when majority followers are inactive",
                 behavior instanceof IsolatedLeader);
-
         }};
     }
 
 
     @Test
     public void testAppendEntryCallAtEndofAppendEntryReply() throws Exception {
-        new JavaTestKit(getSystem()) {{
-            TestActorRef<MessageCollectorActor> leaderActor = TestActorRef.create(getSystem(),
-                    Props.create(MessageCollectorActor.class));
+        logStart("testAppendEntryCallAtEndofAppendEntryReply");
 
-            MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
-
-            DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
-            //configParams.setHeartBeatInterval(new FiniteDuration(9, TimeUnit.SECONDS));
-            configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
+        MockRaftActorContext leaderActorContext = createActorContextWithFollower();
 
-            leaderActorContext.setConfigParams(configParams);
+        DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
+        //configParams.setHeartBeatInterval(new FiniteDuration(9, TimeUnit.SECONDS));
+        configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
 
-            TestActorRef<ForwardMessageToBehaviorActor> followerActor = TestActorRef.create(getSystem(),
-                    ForwardMessageToBehaviorActor.props());
+        leaderActorContext.setConfigParams(configParams);
 
-            MockRaftActorContext followerActorContext =
-                    new MockRaftActorContext("follower-reply", getSystem(), followerActor);
+        MockRaftActorContext followerActorContext = createActorContext(FOLLOWER_ID, followerActor);
 
-            followerActorContext.setConfigParams(configParams);
+        followerActorContext.setConfigParams(configParams);
 
-            Follower follower = new Follower(followerActorContext);
-            followerActor.underlyingActor().behavior = follower;
+        Follower follower = new Follower(followerActorContext);
+        followerActor.underlyingActor().setBehavior(follower);
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower-reply",
-                    followerActor.path().toString());
+        leaderActorContext.getReplicatedLog().removeFrom(0);
+        leaderActorContext.setCommitIndex(-1);
+        leaderActorContext.setLastApplied(-1);
 
-            leaderActorContext.setPeerAddresses(peerAddresses);
+        followerActorContext.getReplicatedLog().removeFrom(0);
+        followerActorContext.setCommitIndex(-1);
+        followerActorContext.setLastApplied(-1);
 
-            leaderActorContext.getReplicatedLog().removeFrom(0);
-            leaderActorContext.setCommitIndex(-1);
-            leaderActorContext.setLastApplied(-1);
+        leader = new Leader(leaderActorContext);
 
-            followerActorContext.getReplicatedLog().removeFrom(0);
-            followerActorContext.setCommitIndex(-1);
-            followerActorContext.setLastApplied(-1);
+        AppendEntriesReply appendEntriesReply = MessageCollectorActor.expectFirstMatching(
+                leaderActor, AppendEntriesReply.class);
 
-            Leader leader = new Leader(leaderActorContext);
+        leader.handleMessage(followerActor, appendEntriesReply);
 
-            AppendEntriesReply appendEntriesReply = MessageCollectorActor.getFirstMatching(
-                    leaderActor, AppendEntriesReply.class);
-            assertNotNull(appendEntriesReply);
-            System.out.println("appendEntriesReply: "+appendEntriesReply);
-            leader.handleMessage(followerActor, appendEntriesReply);
+        // Clear initial heartbeat messages
 
-            // Clear initial heartbeat messages
+        leaderActor.underlyingActor().clear();
+        followerActor.underlyingActor().clear();
 
-            leaderActor.underlyingActor().clear();
-            followerActor.underlyingActor().clear();
+        // create 3 entries
+        leaderActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        leaderActorContext.setCommitIndex(1);
+        leaderActorContext.setLastApplied(1);
 
-            // create 3 entries
-            leaderActorContext.setReplicatedLog(
-                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
-            leaderActorContext.setCommitIndex(1);
-            leaderActorContext.setLastApplied(1);
+        Uninterruptibles.sleepUninterruptibly(leaderActorContext.getConfigParams().getHeartBeatInterval().toMillis(),
+                TimeUnit.MILLISECONDS);
 
-            Uninterruptibles.sleepUninterruptibly(leaderActorContext.getConfigParams().getHeartBeatInterval().toMillis(),
-                    TimeUnit.MILLISECONDS);
+        leader.handleMessage(leaderActor, new SendHeartBeat());
 
-            leader.handleMessage(leaderActor, new SendHeartBeat());
+        AppendEntries appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            AppendEntries appendEntries = MessageCollectorActor.getFirstMatching(followerActor, AppendEntries.class);
-            assertNotNull(appendEntries);
+        // Should send first log entry
+        assertEquals(1, appendEntries.getLeaderCommit());
+        assertEquals(0, appendEntries.getEntries().get(0).getIndex());
+        assertEquals(-1, appendEntries.getPrevLogIndex());
 
-            // Should send first log entry
-            assertEquals(1, appendEntries.getLeaderCommit());
-            assertEquals(0, appendEntries.getEntries().get(0).getIndex());
-            assertEquals(-1, appendEntries.getPrevLogIndex());
+        appendEntriesReply = MessageCollectorActor.expectFirstMatching(leaderActor, AppendEntriesReply.class);
 
-            appendEntriesReply = MessageCollectorActor.getFirstMatching(leaderActor, AppendEntriesReply.class);
-            assertNotNull(appendEntriesReply);
+        assertEquals(1, appendEntriesReply.getLogLastTerm());
+        assertEquals(0, appendEntriesReply.getLogLastIndex());
 
-            assertEquals(1, appendEntriesReply.getLogLastTerm());
-            assertEquals(0, appendEntriesReply.getLogLastIndex());
+        followerActor.underlyingActor().clear();
 
-            followerActor.underlyingActor().clear();
+        leader.handleAppendEntriesReply(followerActor, appendEntriesReply);
 
-            leader.handleAppendEntriesReply(followerActor, appendEntriesReply);
+        appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            appendEntries = MessageCollectorActor.getFirstMatching(followerActor, AppendEntries.class);
-            assertNotNull(appendEntries);
+        // Should send second log entry
+        assertEquals(1, appendEntries.getLeaderCommit());
+        assertEquals(1, appendEntries.getEntries().get(0).getIndex());
 
-            // Should send second log entry
-            assertEquals(1, appendEntries.getLeaderCommit());
-            assertEquals(1, appendEntries.getEntries().get(0).getIndex());
-        }};
+        follower.close();
     }
 
-    class MockLeader extends Leader {
+    @Test
+    public void testLaggingFollowerStarvation() throws Exception {
+        logStart("testLaggingFollowerStarvation");
+        new JavaTestKit(getSystem()) {{
+            String leaderActorId = actorFactory.generateActorId("leader");
+            String follower1ActorId = actorFactory.generateActorId("follower");
+            String follower2ActorId = actorFactory.generateActorId("follower");
 
-        FollowerToSnapshot fts;
+            TestActorRef<ForwardMessageToBehaviorActor> leaderActor =
+                    actorFactory.createTestActor(ForwardMessageToBehaviorActor.props(), leaderActorId);
+            ActorRef follower1Actor = actorFactory.createActor(MessageCollectorActor.props(), follower1ActorId);
+            ActorRef follower2Actor = actorFactory.createActor(MessageCollectorActor.props(), follower2ActorId);
 
-        public MockLeader(RaftActorContext context){
-            super(context);
-        }
+            MockRaftActorContext leaderActorContext =
+                    new MockRaftActorContext(leaderActorId, getSystem(), leaderActor);
 
-        public FollowerToSnapshot getFollowerToSnapshot() {
-            return fts;
-        }
+            DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
+            configParams.setHeartBeatInterval(new FiniteDuration(200, TimeUnit.MILLISECONDS));
+            configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
 
-        public void createFollowerToSnapshot(String followerId, ByteString bs ) {
-            fts = new FollowerToSnapshot(bs);
-            setFollowerSnapshot(followerId, fts);
-        }
+            leaderActorContext.setConfigParams(configParams);
+
+            leaderActorContext.setReplicatedLog(
+                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(1,5,1).build());
+
+            Map<String, String> peerAddresses = new HashMap<>();
+            peerAddresses.put(follower1ActorId,
+                    follower1Actor.path().toString());
+            peerAddresses.put(follower2ActorId,
+                    follower2Actor.path().toString());
+
+            leaderActorContext.setPeerAddresses(peerAddresses);
+            leaderActorContext.getTermInformation().update(1, leaderActorId);
+
+            RaftActorBehavior leader = createBehavior(leaderActorContext);
+
+            leaderActor.underlyingActor().setBehavior(leader);
+
+            for(int i=1;i<6;i++) {
+                // Each AppendEntriesReply could end up rescheduling the heartbeat (without the fix for bug 2733)
+                RaftActorBehavior newBehavior = leader.handleMessage(follower1Actor, new AppendEntriesReply(follower1ActorId, 1, true, i, 1));
+                assertTrue(newBehavior == leader);
+                Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
+            }
+
+            // Check if the leader has been receiving SendHeartbeat messages despite getting AppendEntriesReply
+            List<SendHeartBeat> heartbeats = MessageCollectorActor.getAllMatching(leaderActor, SendHeartBeat.class);
+
+            assertTrue(String.format("%s heartbeat(s) is less than expected", heartbeats.size()),
+                    heartbeats.size() > 1);
+
+            // Check if follower-2 got AppendEntries during this time and was not starved
+            List<AppendEntries> appendEntries = MessageCollectorActor.getAllMatching(follower2Actor, AppendEntries.class);
+
+            assertTrue(String.format("%s append entries is less than expected", appendEntries.size()),
+                    appendEntries.size() > 1);
+
+        }};
+    }
+
+    @Override
+    protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(RaftActorContext actorContext,
+            ActorRef actorRef, RaftRPC rpc) throws Exception {
+        super.assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, actorRef, rpc);
+        assertEquals("New votedFor", null, actorContext.getTermInformation().getVotedFor());
     }
 
     private class MockConfigParamsImpl extends DefaultConfigParamsImpl {
diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/ForwardMessageToBehaviorActor.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/ForwardMessageToBehaviorActor.java
new file mode 100644 (file)
index 0000000..9bcfcd9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.cluster.raft.utils;
+
+import akka.actor.Props;
+import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
+
+public class ForwardMessageToBehaviorActor extends MessageCollectorActor {
+    private RaftActorBehavior behavior;
+
+    @Override
+    public void onReceive(Object message) throws Exception {
+        if(behavior != null) {
+            behavior.handleMessage(sender(), message);
+        }
+
+        super.onReceive(message);
+    }
+
+    public static Props props() {
+        return Props.create(ForwardMessageToBehaviorActor.class);
+    }
+
+    public void setBehavior(RaftActorBehavior behavior){
+        this.behavior = behavior;
+    }
+}
+
index 79c90cf051cc928ac50e563a136c62030809bbc2..62f163fb7d0270a2415e934d193136d610e01ca3 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.cluster.raft.utils;
 
 import akka.actor.ActorRef;
+import akka.actor.Props;
 import akka.actor.UntypedActor;
 import akka.pattern.Patterns;
 import akka.util.Timeout;
@@ -18,6 +19,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import org.junit.Assert;
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
@@ -63,29 +65,46 @@ public class MessageCollectorActor extends UntypedActor {
      * @return
      */
     public static <T> T getFirstMatching(ActorRef actor, Class<T> clazz) throws Exception {
-        for(int i = 0; i < 50; i++) {
-            List<Object> allMessages = getAllMessages(actor);
+        List<Object> allMessages = getAllMessages(actor);
 
-            for(Object message : allMessages){
-                if(message.getClass().equals(clazz)){
-                    return (T) message;
-                }
+        for(Object message : allMessages){
+            if(message.getClass().equals(clazz)){
+                return (T) message;
             }
+        }
+
+        return null;
+    }
 
-            Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
+    public static <T> T expectFirstMatching(ActorRef actor, Class<T> clazz) {
+        return expectFirstMatching(actor, clazz, 5000);
+    }
+
+    public static <T> T expectFirstMatching(ActorRef actor, Class<T> clazz, long timeout) {
+        int count = (int) (timeout / 50);
+        for(int i = 0; i < count; i++) {
+            try {
+                T message = getFirstMatching(actor, clazz);
+                if(message != null) {
+                    return message;
+                }
+            } catch (Exception e) {}
+
+            Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
         }
 
+        Assert.fail("Did not receive message of type " + clazz);
         return null;
     }
 
-    public static List<Object> getAllMatching(ActorRef actor, Class<?> clazz) throws Exception {
+    public static <T> List<T> getAllMatching(ActorRef actor, Class<T> clazz) throws Exception {
         List<Object> allMessages = getAllMessages(actor);
 
-        List<Object> output = Lists.newArrayList();
+        List<T> output = Lists.newArrayList();
 
         for(Object message : allMessages){
             if(message.getClass().equals(clazz)){
-                output.add(message);
+                output.add((T) message);
             }
         }
 
@@ -105,4 +124,8 @@ public class MessageCollectorActor extends UntypedActor {
 
         throw new TimeoutException("Actor not ready in time.");
     }
+
+    public static Props props() {
+        return Props.create(MessageCollectorActor.class);
+    }
 }
index 4e798073f6e7fc19f1587f9e1905b6778e34df63..853fc755d20880e8e326a7c81b81b778955c9e2d 100644 (file)
@@ -3,4 +3,4 @@ org.slf4j.simpleLogger.dateTimeFormat=hh:mm:ss,S a
 org.slf4j.simpleLogger.logFile=System.out
 org.slf4j.simpleLogger.showShortLogName=true
 org.slf4j.simpleLogger.levelInBrackets=true
-org.slf4j.simpleLogger.org.opendaylight.controller.cluster.raft=trace
\ No newline at end of file
+org.slf4j.simpleLogger.log.org.opendaylight.controller.cluster.raft=trace
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataObjectModification.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataObjectModification.java
new file mode 100644 (file)
index 0000000..2eee0e8
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+/**
+ * Modified Data Object.
+ *
+ * Represents modification of Data Object.
+ *
+ */
+public interface DataObjectModification<T extends DataObject> extends Identifiable<PathArgument> {
+
+    enum ModificationType {
+        /**
+         *
+         * Child node (direct or indirect) was modified.
+         *
+         */
+        SUBTREE_MODIFIED,
+        /**
+         *
+         * Node was explicitly created / overwritten.
+         *
+         */
+        WRITE,
+        /**
+         *
+         * Node was deleted.
+         *
+         */
+        DELETE
+    }
+
+    @Override
+    PathArgument getIdentifier();
+
+    /**
+     * Returns type of modified object.
+     *
+     * @return type of modified object.
+     */
+    @Nonnull Class<T> getDataType();
+
+    /**
+     *
+     * Returns type of modification
+     *
+     * @return type Type of performed modification.
+     */
+    @Nonnull ModificationType getModificationType();
+
+    /**
+     * Returns after state of top level container.
+     *
+     * @param root Class representing data container
+     * @return State of object after modification. Null if subtree is not present.
+     */
+    @Nullable T getDataAfter();
+
+    /**
+     * Returns unmodifiable collection of modified direct children.
+     *
+     * @return unmodifiable collection of modified direct children.
+     */
+    @Nonnull Collection<DataObjectModification<? extends DataObject>> getModifiedChildren();
+
+
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeListener.java
new file mode 100644 (file)
index 0000000..6b1df71
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import java.util.Collection;
+import java.util.EventListener;
+import javax.annotation.Nonnull;
+
+/**
+ * Interface implemented by classes interested in receiving notifications about
+ * data tree changes. This interface differs from {@link DataChangeListener}
+ * in that it provides a cursor-based view of the change, which has potentially
+ * lower overhead and allow more flexible consumption of change event.
+ */
+public interface DataTreeChangeListener extends EventListener {
+    /**
+     * Invoked when there was data change for the supplied path, which was used
+     * to register this listener.
+     *
+     * <p>
+     * This method may be also invoked during registration of the listener if
+     * there is any pre-existing data in the conceptual data tree for supplied
+     * path. This initial event will contain all pre-existing data as created.
+     *
+     * <p>
+     * A data change event may be triggered spuriously, e.g. such that data before
+     * and after compare as equal. Implementations of this interface are expected
+     * to recover from such events. Event producers are expected to exert reasonable
+     * effort to suppress such events.
+     *
+     * In other words, it is completely acceptable to observe
+     * a {@link DataObjectModification}, while the state observed before and
+     * after- data items compare as equal.
+     *
+     * @param changes Collection of change events, may not be null or empty.
+     */
+    void onDataTreeChanged(@Nonnull Collection<DataTreeModification> changes);
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeChangeService.java
new file mode 100644 (file)
index 0000000..ae4e36f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * A {@link DOMService} which allows users to register for changes to a
+ * subtree.
+ */
+public interface DataTreeChangeService extends BindingService {
+    /**
+     * Registers a {@link DataTreeChangeListener} to receive
+     * notifications when data changes under a given path in the conceptual data
+     * tree.
+     * <p>
+     * You are able to register for notifications  for any node or subtree
+     * which can be represented using {@link DataTreeIdentifier}.
+     * <p>
+     *
+     * You are able to register for data change notifications for a subtree or leaf
+     * even if it does not exist. You will receive notification once that node is
+     * created.
+     * <p>
+     * If there is any pre-existing data in the data tree for the path for which you are
+     * registering, you will receive an initial data change event, which will
+     * contain all pre-existing data, marked as created.
+     *
+     * <p>
+     * This method returns a {@link ListenerRegistration} object. To
+     * "unregister" your listener for changes call the {@link ListenerRegistration#close()}
+     * method on the returned object.
+     * <p>
+     * You MUST explicitly unregister your listener when you no longer want to receive
+     * notifications. This is especially true in OSGi environments, where failure to
+     * do so during bundle shutdown can lead to stale listeners being still registered.
+     *
+     * @param treeId
+     *            Data tree identifier of the subtree which should be watched for
+     *            changes.
+     * @param listener
+     *            Listener instance which is being registered
+     * @return Listener registration object, which may be used to unregister
+     *         your listener using {@link ListenerRegistration#close()} to stop
+     *         delivery of change events.
+     */
+    @Nonnull <L extends DataTreeChangeListener> ListenerRegistration<L> registerDataTreeChangeListener(@Nonnull DataTreeIdentifier treeId, @Nonnull L listener);
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeIdentifier.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeIdentifier.java
new file mode 100644 (file)
index 0000000..428957e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.binding.api;
+
+import com.google.common.base.Preconditions;
+import java.io.Serializable;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * A unique identifier for a particular subtree. It is composed of the logical
+ * data store type and the instance identifier of the root node.
+ */
+public final class DataTreeIdentifier implements Immutable, Path<DataTreeIdentifier>, Serializable {
+    private static final long serialVersionUID = 1L;
+    private final InstanceIdentifier<?> rootIdentifier;
+    private final LogicalDatastoreType datastoreType;
+
+    public DataTreeIdentifier(final LogicalDatastoreType datastoreType, final InstanceIdentifier<?> rootIdentifier) {
+        this.datastoreType = Preconditions.checkNotNull(datastoreType);
+        this.rootIdentifier = Preconditions.checkNotNull(rootIdentifier);
+    }
+
+    /**
+     * Return the logical data store type.
+     *
+     * @return Logical data store type. Guaranteed to be non-null.
+     */
+    public @Nonnull LogicalDatastoreType getDatastoreType() {
+        return datastoreType;
+    }
+
+    /**
+     * Return the {@link YangInstanceIdentifier} of the root node.
+     *
+     * @return Instance identifier corresponding to the root node.
+     */
+    public @Nonnull InstanceIdentifier<?> getRootIdentifier() {
+        return rootIdentifier;
+    }
+
+    @Override
+    public boolean contains(final DataTreeIdentifier other) {
+        return datastoreType == other.datastoreType && rootIdentifier.contains(other.rootIdentifier);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + datastoreType.hashCode();
+        result = prime * result + rootIdentifier.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof DataTreeIdentifier)) {
+            return false;
+        }
+        DataTreeIdentifier other = (DataTreeIdentifier) obj;
+        if (datastoreType != other.datastoreType) {
+            return false;
+        }
+        return rootIdentifier.equals(other.rootIdentifier);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeModification.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataTreeModification.java
new file mode 100644 (file)
index 0000000..aac51a6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.md.sal.binding.api;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+/**
+ * Represent root of modification.
+ *
+ * @author Tony Tkacik &lt;ttkacik@cisco.com&gt;
+ *
+ */
+public interface DataTreeModification {
+
+    /**
+     * Get the modification root path. This is the path of the root node
+     * relative to the root of InstanceIdentifier namespace.
+     *
+     * @return absolute path of the root node
+     */
+    @Nonnull DataTreeIdentifier getRootPath();
+
+    /**
+     * Get the modification root node.
+     *
+     * @return modification root node
+     */
+    @Nonnull DataObjectModification<? extends DataObject> getRootNode();
+
+}
index 01cd1f88ba0e29f5391ac3a07330cc10fb940606..d6a5e498b658a64356950c0f1de5238d018970a2 100644 (file)
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.model</groupId>
-      <artifactId>model-flow-service</artifactId>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.ops4j.pax.exam</groupId>
       <artifactId>pax-exam-container-native</artifactId>
       <artifactId>yang-parser-impl</artifactId>
       <scope>test</scope>
     </dependency>
-      <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>sal-test-model</artifactId>
-      </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-test-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>opendaylight-l2-types</artifactId>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
index aefc53b124335b5801910faaed56adca6be32d46..3d25018e247daf848f517746f73ff6e79bf9b89d 100644 (file)
@@ -17,26 +17,25 @@ import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 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.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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
-/*
+/**
  * FIXME: THis test should be moved to sal-binding-broker and rewriten
  * to use new DataBroker API
  */
 @SuppressWarnings("deprecation")
 public class ConcurrentImplicitCreateTest extends AbstractDataServiceTest {
 
-    private static final NodeKey NODE_FOO_KEY = new NodeKey(new NodeId("foo"));
-    private static final NodeKey NODE_BAR_KEY = new NodeKey(new NodeId("foo"));
-    private static InstanceIdentifier<Nodes> NODES_PATH = InstanceIdentifier.builder(Nodes.class).build();
-    private static InstanceIdentifier<Node> NODE_FOO_PATH = NODES_PATH.child(Node.class, NODE_FOO_KEY);
-    private static InstanceIdentifier<Node> NODE_BAR_PATH = NODES_PATH.child(Node.class, NODE_FOO_KEY);
+    private static final TopLevelListKey FOO_KEY = new TopLevelListKey("foo");
+    private static final TopLevelListKey BAR_KEY = new TopLevelListKey("bar");
+    private static InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.builder(Top.class).build();
+    private static InstanceIdentifier<TopLevelList> FOO_PATH = TOP_PATH.child(TopLevelList.class, FOO_KEY);
+    private static InstanceIdentifier<TopLevelList> BAR_PATH = TOP_PATH.child(TopLevelList.class, BAR_KEY);
 
     @Test
     public void testConcurrentCreate() throws InterruptedException, ExecutionException {
@@ -44,8 +43,8 @@ public class ConcurrentImplicitCreateTest extends AbstractDataServiceTest {
         DataModificationTransaction fooTx = baDataService.beginTransaction();
         DataModificationTransaction barTx = baDataService.beginTransaction();
 
-        fooTx.putOperationalData(NODE_FOO_PATH, new NodeBuilder().setKey(NODE_FOO_KEY).build());
-        barTx.putOperationalData(NODE_BAR_PATH, new NodeBuilder().setKey(NODE_BAR_KEY).build());
+        fooTx.putOperationalData(FOO_PATH, new TopLevelListBuilder().setKey(FOO_KEY).build());
+        barTx.putOperationalData(BAR_PATH, new TopLevelListBuilder().setKey(BAR_KEY).build());
 
         Future<RpcResult<TransactionStatus>> fooFuture = fooTx.commit();
         Future<RpcResult<TransactionStatus>> barFuture = barTx.commit();
index 2b5171369bb31a7195b029c1377201c76ba24849..0a611a75d0ed2bd57fe27a6fd9117068ca1cf230 100644 (file)
@@ -22,87 +22,75 @@ 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.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.FlowId;
-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.TableBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.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.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ContainerWithUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ListViaUsesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 import com.google.common.util.concurrent.SettableFuture;
 
-/*
- * FIXME: THis test should be moved to compat test-suite and rewriten
- * to use sal-test-model
+/**
+ * FIXME: THis test should be moved to compat test-suite
  */
 @SuppressWarnings("deprecation")
 public class WildcardedDataChangeListenerTest extends AbstractDataServiceTest {
 
-    private static final NodeKey NODE_0_KEY = new NodeKey(new NodeId("test:0"));
-    private static final NodeKey NODE_1_KEY = new NodeKey(new NodeId("test:1"));
+    private static final TopLevelListKey TOP_LEVEL_LIST_0_KEY = new TopLevelListKey("test:0");
+    private static final TopLevelListKey TOP_LEVEL_LIST_1_KEY = new TopLevelListKey("test:1");
 
-    public static final InstanceIdentifier<Flow> DEEP_WILDCARDED_PATH = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class) //
-            .augmentation(FlowCapableNode.class) //
-            .child(Table.class) //
-            .child(Flow.class) //
+    protected static final InstanceIdentifier<ListViaUses> DEEP_WILDCARDED_PATH = InstanceIdentifier
+            .builder(Top.class)
+            .child(TopLevelList.class) //
+            .augmentation(TreeComplexUsesAugment.class) //
+            .child(ListViaUses.class) //
             .build();
 
-    private static final TableKey TABLE_0_KEY = new TableKey((short) 0);
-    private static final TableFeaturesKey TABLE_FEATURES_KEY = new TableFeaturesKey((short) 0);
-
-    private static final InstanceIdentifier<Table> NODE_0_TABLE_PATH = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class, NODE_0_KEY) //
-            .augmentation(FlowCapableNode.class) //
-            .child(Table.class, TABLE_0_KEY) //
+    private static final InstanceIdentifier<TreeComplexUsesAugment> NODE_0_TCU_PATH = InstanceIdentifier
+            .builder(Top.class)
+            .child(TopLevelList.class, TOP_LEVEL_LIST_0_KEY) //
+            .augmentation(TreeComplexUsesAugment.class) //
             .build();
 
-    private static final InstanceIdentifier<Table> NODE_1_TABLE_PATH = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class, NODE_1_KEY) //
-            .augmentation(FlowCapableNode.class) //
-            .child(Table.class, TABLE_0_KEY) //
+    private static final InstanceIdentifier<TreeComplexUsesAugment> NODE_1_TCU_PATH = InstanceIdentifier
+            .builder(Top.class)
+            .child(TopLevelList.class, TOP_LEVEL_LIST_1_KEY) //
+            .augmentation(TreeComplexUsesAugment.class) //
             .build();
 
-    private static final FlowKey FLOW_KEY = new FlowKey(new FlowId("test"));
 
-    private static final InstanceIdentifier<Flow> NODE_0_FLOW_PATH = NODE_0_TABLE_PATH.child(Flow.class, FLOW_KEY);
+    private static final ListViaUsesKey LIST_VIA_USES_KEY = new ListViaUsesKey("test");
+
+    private static final InstanceIdentifier<ListViaUses> NODE_0_LVU_PATH = NODE_0_TCU_PATH.child(ListViaUses.class, LIST_VIA_USES_KEY);
 
-    private static final InstanceIdentifier<Flow> NODE_1_FLOW_PATH = NODE_1_TABLE_PATH.child(Flow.class, FLOW_KEY);
+    private static final InstanceIdentifier<ListViaUses> NODE_1_LVU_PATH = NODE_1_TCU_PATH.child(ListViaUses.class, LIST_VIA_USES_KEY);
 
-    private static final InstanceIdentifier<TableFeatures> NODE_0_TABLE_FEATURES_PATH =
-            NODE_0_TABLE_PATH.child(TableFeatures.class, TABLE_FEATURES_KEY);
+    private static final InstanceIdentifier<ContainerWithUses> NODE_0_CWU_PATH =
+            NODE_0_TCU_PATH.child(ContainerWithUses.class);
 
-    private static final TableFeatures TABLE_FEATURES = new TableFeaturesBuilder()//
-            .setKey(TABLE_FEATURES_KEY) //
-            .setName("Foo") //
-            .setMaxEntries(1000L) //
+    private static final ContainerWithUses CWU= new ContainerWithUsesBuilder()//
+            .setLeafFromGrouping("some container value") //
             .build();
 
-    private static final Flow FLOW = new FlowBuilder() //
-            .setKey(FLOW_KEY) //
-            .setBarrier(true) //
-            .setStrict(true) //
+    private static final ListViaUses LVU = new ListViaUsesBuilder() //
+            .setKey(LIST_VIA_USES_KEY) //
+            .setName("john")
             .build();
 
     @Test
-    public void testSepareteWrites() throws InterruptedException, TimeoutException, ExecutionException {
+    public void testSeparateWrites() throws InterruptedException, TimeoutException, ExecutionException {
 
         DataProviderService dataBroker = testContext.getBindingDataBroker();
 
         final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> eventFuture = SettableFuture.create();
         dataBroker.registerDataChangeListener(DEEP_WILDCARDED_PATH, new DataChangeListener() {
-
             @Override
             public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> dataChangeEvent) {
                 eventFuture.set(dataChangeEvent);
@@ -110,9 +98,9 @@ public class WildcardedDataChangeListenerTest extends AbstractDataServiceTest {
         });
 
         DataModificationTransaction transaction = dataBroker.beginTransaction();
-        transaction.putOperationalData(NODE_0_TABLE_FEATURES_PATH, TABLE_FEATURES);
-        transaction.putOperationalData(NODE_0_FLOW_PATH, FLOW);
-        transaction.putOperationalData(NODE_1_FLOW_PATH, FLOW);
+        transaction.putOperationalData(NODE_0_CWU_PATH, CWU);
+        transaction.putOperationalData(NODE_0_LVU_PATH, LVU);
+        transaction.putOperationalData(NODE_1_LVU_PATH, LVU);
         transaction.commit().get();
 
         DataChangeEvent<InstanceIdentifier<?>, DataObject> event = eventFuture.get(1000, TimeUnit.MILLISECONDS);
@@ -127,29 +115,26 @@ public class WildcardedDataChangeListenerTest extends AbstractDataServiceTest {
 
         final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> eventFuture = SettableFuture.create();
         dataBroker.registerDataChangeListener(DEEP_WILDCARDED_PATH, new DataChangeListener() {
-
             @Override
             public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> dataChangeEvent) {
                 eventFuture.set(dataChangeEvent);
             }
         });
 
-        DataModificationTransaction tableTx = dataBroker.beginTransaction();
-        tableTx.putOperationalData(NODE_0_TABLE_FEATURES_PATH, TABLE_FEATURES);
-        tableTx.commit().get();
+        DataModificationTransaction cwuTx = dataBroker.beginTransaction();
+        cwuTx.putOperationalData(NODE_0_CWU_PATH, CWU);
+        cwuTx.commit().get();
 
         assertFalse(eventFuture.isDone());
 
-        DataModificationTransaction flowTx = dataBroker.beginTransaction();
+        DataModificationTransaction lvuTx = dataBroker.beginTransaction();
 
-        Table table = new TableBuilder() //
-                .setKey(TABLE_0_KEY) //
-                .setFlow(Collections.singletonList(FLOW)) //
-                .build();
+        TreeComplexUsesAugment tcua = new TreeComplexUsesAugmentBuilder()
+                .setListViaUses(Collections.singletonList(LVU)).build();
 
-        flowTx.putOperationalData(NODE_0_TABLE_PATH, table);
-        flowTx.putOperationalData(NODE_1_FLOW_PATH, FLOW);
-        flowTx.commit().get();
+        lvuTx.putOperationalData(NODE_0_TCU_PATH, tcua);
+        lvuTx.putOperationalData(NODE_1_LVU_PATH, LVU);
+        lvuTx.commit().get();
 
         validateEvent(eventFuture.get(1000, TimeUnit.MILLISECONDS));
     }
@@ -161,7 +146,7 @@ public class WildcardedDataChangeListenerTest extends AbstractDataServiceTest {
 
         // We wrote initial state NODE_0_FLOW
         DataModificationTransaction transaction = dataBroker.beginTransaction();
-        transaction.putOperationalData(NODE_0_FLOW_PATH, FLOW);
+        transaction.putOperationalData(NODE_0_LVU_PATH, LVU);
         transaction.commit().get();
 
         // We registered DataChangeListener
@@ -176,23 +161,23 @@ public class WildcardedDataChangeListenerTest extends AbstractDataServiceTest {
         assertFalse(eventFuture.isDone());
 
         DataModificationTransaction secondTx = dataBroker.beginTransaction();
-        secondTx.putOperationalData(NODE_0_FLOW_PATH, FLOW);
-        secondTx.putOperationalData(NODE_1_FLOW_PATH, FLOW);
+        secondTx.putOperationalData(NODE_0_LVU_PATH, LVU);
+        secondTx.putOperationalData(NODE_1_LVU_PATH, LVU);
         secondTx.commit().get();
 
         DataChangeEvent<InstanceIdentifier<?>, DataObject> event = (eventFuture.get(1000, TimeUnit.MILLISECONDS));
         assertNotNull(event);
         // Data change should contains NODE_1 Flow - which was added
-        assertTrue(event.getCreatedOperationalData().containsKey(NODE_1_FLOW_PATH));
+        assertTrue(event.getCreatedOperationalData().containsKey(NODE_1_LVU_PATH));
         // Data change must not containe NODE_0 Flow which was replaced with same value.
-        assertFalse(event.getUpdatedOperationalData().containsKey(NODE_0_FLOW_PATH));
+        assertFalse(event.getUpdatedOperationalData().containsKey(NODE_0_LVU_PATH));
     }
 
     private static void validateEvent(final DataChangeEvent<InstanceIdentifier<?>, DataObject> event) {
         assertNotNull(event);
-        assertTrue(event.getCreatedOperationalData().containsKey(NODE_1_FLOW_PATH));
-        assertTrue(event.getCreatedOperationalData().containsKey(NODE_0_FLOW_PATH));
-        assertFalse(event.getCreatedOperationalData().containsKey(NODE_0_TABLE_FEATURES_PATH));
+        assertTrue(event.getCreatedOperationalData().containsKey(NODE_1_LVU_PATH));
+        assertTrue(event.getCreatedOperationalData().containsKey(NODE_0_LVU_PATH));
+        assertFalse(event.getCreatedOperationalData().containsKey(NODE_0_CWU_PATH));
     }
 
 }
index bddbc4e95400965da7533b3d66dfee72fa6c3710..d85cb7a0a2819670e818dd974126bdea6292f36c 100644 (file)
@@ -21,9 +21,9 @@ import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
 import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
@@ -33,7 +33,7 @@ import com.google.common.util.concurrent.MoreExecutors;
 @SuppressWarnings("deprecation")
 public class DOMCodecBug02Test extends AbstractDataServiceTest {
 
-    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+    private static final InstanceIdentifier<Top> TOP_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
             .toInstance();
 
     /**
@@ -66,10 +66,10 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
                 .submit(new Callable<Future<RpcResult<TransactionStatus>>>() {
                     @Override
                     public Future<RpcResult<TransactionStatus>> call() throws Exception {
-                        NodesBuilder nodesBuilder = new NodesBuilder();
-                        nodesBuilder.setNode(Collections.<Node> emptyList());
+                        TopBuilder topBuilder = new TopBuilder();
+                        topBuilder.setTopLevelList(Collections.<TopLevelList> emptyList());
                         DataModificationTransaction transaction = baDataService.beginTransaction();
-                        transaction.putOperationalData(NODES_INSTANCE_ID_BA, nodesBuilder.build());
+                        transaction.putOperationalData(TOP_INSTANCE_ID_BA, topBuilder.build());
                         return transaction.commit();
                     }
                 });
@@ -77,13 +77,13 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
         RpcResult<TransactionStatus> result = future.get().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        Nodes nodes = checkForNodes();
-        assertNotNull(nodes);
+        Top top = checkForTop();
+        assertNotNull(top);
 
     }
 
-    private Nodes checkForNodes() {
-        return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+    private Top checkForTop() {
+        return (Top) baDataService.readOperationalData(TOP_INSTANCE_ID_BA);
 
     }
 
index c07125a5dcce9b2130c37e8f99feb646252e54ad..ba4a024b7cd3cd579e5aac7ac00f8976d4545287 100644 (file)
@@ -22,22 +22,20 @@ 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.flow.inventory.rev130819.flow.node.SupportedActions;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-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.SupportType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.CustomEnum;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.Cont2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.Cont2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.cont2.Contlist1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.cont2.Contlist1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -49,42 +47,42 @@ import com.google.common.util.concurrent.SettableFuture;
 @SuppressWarnings("deprecation")
 public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataChangeListener {
 
-    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
-    private static final String NODE_ID = "openflow:1";
+    private static final QName TOP_LEVEL_LIST_NAME_QNAME = QName.create(TopLevelList.QNAME, "name");
+    private static final String TOP_LEVEL_LIST_NAME = "tll:foo";
 
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+    private static final TopLevelListKey TLL_KEY = new TopLevelListKey(TOP_LEVEL_LIST_NAME);
 
-    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
-            NODE_ID);
+    private static final Map<QName, Object> TLL_KEY_BI = Collections.<QName, Object> singletonMap(TOP_LEVEL_LIST_NAME_QNAME,
+            TOP_LEVEL_LIST_NAME);
 
-    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+    private static final InstanceIdentifier<Top> TOP_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
             .toInstance();
 
 
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = NODES_INSTANCE_ID_BA.child(Node.class, NODE_KEY);
+    private static final InstanceIdentifier<TopLevelList> TLL_INSTANCE_ID_BA = TOP_INSTANCE_ID_BA.child(TopLevelList.class, TLL_KEY);
 
 
-    private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = //
-            NODES_INSTANCE_ID_BA.builder() //
-            .child(Node.class, NODE_KEY) //
-            .augmentation(FlowCapableNode.class) //
-            .child(SupportedActions.class)
+    private static final InstanceIdentifier<Cont2> CONT2_INSTANCE_ID_BA = //
+            TOP_INSTANCE_ID_BA.builder() //
+            .child(TopLevelList.class, TLL_KEY) //
+            .augmentation(TllComplexAugment.class) //
+            .child(Cont2.class)
             .toInstance();
 
 
-    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier NODE_INSTANCE_ID_BI = //
+    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier TLL_INSTANCE_ID_BI = //
     org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder() //
-            .node(Nodes.QNAME) //
-            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .node(Top.QNAME) //
+            .nodeWithKey(TopLevelList.QNAME, TLL_KEY_BI) //
             .toInstance();
-    private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
+    private static final QName CONT2_QNAME = QName.create(TllComplexAugment.QNAME, Cont2.QNAME.getLocalName());
 
 
-    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
+    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier CONT2_INSTANCE_ID_BI = //
             org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder() //
-                    .node(Nodes.QNAME) //
-                    .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
-                    .node(SUPPORTED_ACTIONS_QNAME) //
+                    .node(Top.QNAME) //
+                    .nodeWithKey(TopLevelList.QNAME, TLL_KEY_BI) //
+                    .node(CONT2_QNAME) //
                     .toInstance();
 
     private final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> receivedChangeEvent = SettableFuture.create();
@@ -100,24 +98,22 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
     public void testAugmentSerialization() throws Exception {
 
 
-        baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
+        baDataService.registerDataChangeListener(TOP_INSTANCE_ID_BA, this);
 
-        NodeBuilder nodeBuilder = new NodeBuilder();
-        nodeBuilder.setId(new NodeId(NODE_ID));
-        nodeBuilder.setKey(NODE_KEY);
+        TopLevelListBuilder tllBuilder = new TopLevelListBuilder();
+        tllBuilder.setKey(TLL_KEY);
         DataModificationTransaction transaction = baDataService.beginTransaction();
 
 
-        FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
-        fnub.setHardware("Hardware Foo");
-        fnub.setManufacturer("Manufacturer Foo");
-        fnub.setSerialNumber("Serial Foo");
-        fnub.setDescription("Description Foo");
-        fnub.setSoftware("JUnit emulated");
-        FlowCapableNode fnu = fnub.build();
-        nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
-        Node original = nodeBuilder.build();
-        transaction.putOperationalData(NODE_INSTANCE_ID_BA, original);
+        TllComplexAugmentBuilder tllcab = new TllComplexAugmentBuilder();
+        tllcab.setAttrStr1("Hardware Foo");
+        tllcab.setAttrStr2("Manufacturer Foo");
+        tllcab.setAttrStr3("Serial Foo");
+        tllcab.setAttrStr4("Description Foo");
+        TllComplexAugment tlca = tllcab.build();
+        tllBuilder.addAugmentation(TllComplexAugment.class, tlca);
+        TopLevelList original = tllBuilder.build();
+        transaction.putOperationalData(TLL_INSTANCE_ID_BA, original);
 
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
@@ -125,13 +121,13 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
         DataChangeEvent<InstanceIdentifier<?>, DataObject> potential = receivedChangeEvent.get(1000,TimeUnit.MILLISECONDS);
         assertNotNull(potential);
 
-        verifyNodes((Nodes) potential.getUpdatedOperationalSubtree(),original);
-        assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
-        Nodes nodes = checkForNodes();
-        verifyNodes(nodes,original);
+        verifyTll((Top) potential.getUpdatedOperationalSubtree(),original);
+        assertBindingIndependentVersion(TLL_INSTANCE_ID_BI);
+        Top top = checkForTop();
+        verifyTll(top,original);
 
         testAddingNodeConnector();
-        testNodeRemove();
+        testTllRemove();
 
     }
 
@@ -139,69 +135,66 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
     public void testAugmentNestedSerialization() throws Exception {
         DataModificationTransaction transaction = baDataService.beginTransaction();
 
-        SupportedActionsBuilder actions = new SupportedActionsBuilder();
-        ActionTypeBuilder action = new ActionTypeBuilder();
-        action.setAction("foo-action");
-        action.setSupportState(SupportType.Native);
-        List<ActionType> actionTypes = Collections.singletonList(action.build());
-        actions.setActionType(actionTypes );
+        Cont2Builder cont2b = new Cont2Builder();
+        Contlist1Builder cl1b = new Contlist1Builder();
+        cl1b.setAttrStr("foo-action");
+        cl1b.setAttrEnum(CustomEnum.Type1);
+        List<Contlist1> contlists = Collections.singletonList(cl1b.build());
+        cont2b.setContlist1(contlists);
 
-        transaction.putOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA, actions.build());
+        transaction.putOperationalData(CONT2_INSTANCE_ID_BA, cont2b.build());
         RpcResult<TransactionStatus> putResult = transaction.commit().get();
         assertNotNull(putResult);
         assertEquals(TransactionStatus.COMMITED, putResult.getResult());
-        SupportedActions readedTable = (SupportedActions) baDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA);
+        Cont2 readedTable = (Cont2) baDataService.readOperationalData(CONT2_INSTANCE_ID_BA);
         assertNotNull(readedTable);
 
-        CompositeNode biSupportedActions = biDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BI);
+        CompositeNode biSupportedActions = biDataService.readOperationalData(CONT2_INSTANCE_ID_BI);
         assertNotNull(biSupportedActions);
 
     }
 
     private void testAddingNodeConnector() throws Exception {
-
-        NodeConnectorId ncId = new NodeConnectorId("openflow:1:bar");
-        NodeConnectorKey nodeKey = new NodeConnectorKey(ncId );
-        InstanceIdentifier<NodeConnector> ncInstanceId = NODE_INSTANCE_ID_BA.child(NodeConnector.class, nodeKey);
-        NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder();
-        ncBuilder.setId(ncId);
-        ncBuilder.setKey(nodeKey);
-        NodeConnector connector = ncBuilder.build();
+        NestedListKey nlKey = new NestedListKey("test:0:0");
+        InstanceIdentifier<NestedList> ncInstanceId = TLL_INSTANCE_ID_BA.child(NestedList.class, nlKey);
+        NestedListBuilder nlBuilder = new NestedListBuilder();
+        nlBuilder.setKey(nlKey);
+        NestedList nestedList = nlBuilder.build();
         DataModificationTransaction transaction = baDataService.beginTransaction();
-        transaction.putOperationalData(ncInstanceId, connector);
+        transaction.putOperationalData(ncInstanceId, nestedList);
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
-        assertNotNull(node);
-        assertNotNull(node.getNodeConnector());
-        assertFalse(node.getNodeConnector().isEmpty());
-        NodeConnector readedNc = node.getNodeConnector().get(0);
-        assertNotNull(readedNc);
+        TopLevelList tll = (TopLevelList) baDataService.readOperationalData(TLL_INSTANCE_ID_BA);
+        assertNotNull(tll);
+        assertNotNull(tll.getNestedList());
+        assertFalse(tll.getNestedList().isEmpty());
+        NestedList readedNl = tll.getNestedList().get(0);
+        assertNotNull(readedNl);
     }
 
-    private void testNodeRemove() throws Exception {
+    private void testTllRemove() throws Exception {
         DataModificationTransaction transaction = baDataService.beginTransaction();
-        transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
+        transaction.removeOperationalData(TLL_INSTANCE_ID_BA);
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
-        assertNull(node);
+        TopLevelList tll = (TopLevelList) baDataService.readOperationalData(TLL_INSTANCE_ID_BA);
+        assertNull(tll);
     }
 
-    private void verifyNodes(final Nodes nodes,final Node original) {
-        assertNotNull(nodes);
-        assertNotNull(nodes.getNode());
-        assertEquals(1, nodes.getNode().size());
-        Node readedNode = nodes.getNode().get(0);
-        assertEquals(original.getId(), readedNode.getId());
+    private void verifyTll(final Top top,final TopLevelList original) {
+        assertNotNull(top);
+        assertNotNull(top.getTopLevelList());
+        assertEquals(1, top.getTopLevelList().size());
+        TopLevelList readedNode = top.getTopLevelList().get(0);
+        assertEquals(original.getName(), readedNode.getName());
         assertEquals(original.getKey(), readedNode.getKey());
 
-        FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
-        FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
+        TllComplexAugment fnu = original.getAugmentation(TllComplexAugment.class);
+        TllComplexAugment readedAugment = readedNode.getAugmentation(TllComplexAugment.class);
         assertNotNull(fnu);
-        assertEquals(fnu.getDescription(), readedAugment.getDescription());
-        assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
+        assertEquals(fnu.getAttrStr2(), readedAugment.getAttrStr2());
+        assertEquals(fnu.getAttrStr3(), readedAugment.getAttrStr3());
 
     }
 
@@ -211,8 +204,8 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
         assertNotNull(node);
     }
 
-    private Nodes checkForNodes() {
-        return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+    private Top checkForTop() {
+        return (Top) baDataService.readOperationalData(TOP_INSTANCE_ID_BA);
     }
 
     @Override
index 735138a530ab801149adbaceb79e38c3b27d92b9..40d4591001212c05e716f9fd6b2898d37cc47267 100644 (file)
@@ -9,21 +9,17 @@ 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.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
-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.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.List11SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.List11SimpleAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -32,20 +28,20 @@ import com.google.common.util.concurrent.SettableFuture;
 @SuppressWarnings("deprecation")
 public class DeleteNestedAugmentationListenParentTest extends AbstractDataServiceTest {
 
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId("foo"));
+    private static final TopLevelListKey FOO_KEY = new TopLevelListKey("foo");
 
-    private static final TableKey TABLE_KEY = new TableKey((short) 0);
+    private static final List1Key LIST1_KEY = new List1Key("one");
 
-    private static final FlowKey FLOW_KEY = new FlowKey(new FlowId("100"));
+    private static final List11Key LIST11_KEY = new List11Key(100);
 
-    private static final InstanceIdentifier<FlowCapableNode> NODE_AUGMENT_PATH = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class,NODE_KEY)
-            .augmentation(FlowCapableNode.class)
+    private static final InstanceIdentifier<TllComplexAugment> TLL_COMPLEX_AUGMENT_PATH = InstanceIdentifier.builder(Top.class)
+            .child(TopLevelList.class,FOO_KEY)
+            .augmentation(TllComplexAugment.class)
             .build();
 
-    private static final InstanceIdentifier<Flow> FLOW_PATH = NODE_AUGMENT_PATH.builder()
-            .child(Table.class,TABLE_KEY)
-            .child(Flow.class,FLOW_KEY)
+    private static final InstanceIdentifier<List11> LIST11_PATH = TLL_COMPLEX_AUGMENT_PATH.builder()
+            .child(List1.class,LIST1_KEY)
+            .child(List11.class,LIST11_KEY)
             .build();
 
 
@@ -53,12 +49,12 @@ public class DeleteNestedAugmentationListenParentTest extends AbstractDataServic
     public void deleteChildListenParent() throws InterruptedException, ExecutionException {
         DataModificationTransaction initTx = baDataService.beginTransaction();
 
-        initTx.putOperationalData(FLOW_PATH, flow());
+        initTx.putOperationalData(LIST11_PATH, createList11());
         initTx.commit().get();
 
         final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> event = SettableFuture.create();
 
-        baDataService.registerDataChangeListener(FLOW_PATH, new DataChangeListener() {
+        baDataService.registerDataChangeListener(LIST11_PATH, new DataChangeListener() {
 
             @Override
             public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
@@ -67,23 +63,19 @@ public class DeleteNestedAugmentationListenParentTest extends AbstractDataServic
         });
 
         DataModificationTransaction deleteTx = baDataService.beginTransaction();
-        deleteTx.removeOperationalData(FLOW_PATH.augmentation(FlowStatisticsData.class));
+        deleteTx.removeOperationalData(LIST11_PATH.augmentation(List11SimpleAugment.class));
         deleteTx.commit().get();
 
         DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedEvent = event.get();
-        assertFalse(receivedEvent.getRemovedOperationalData().contains(NODE_AUGMENT_PATH));
+        assertFalse(receivedEvent.getRemovedOperationalData().contains(TLL_COMPLEX_AUGMENT_PATH));
     }
 
-    private Flow flow() {
-        FlowBuilder builder = new FlowBuilder()
-            .setKey(FLOW_KEY)
-            .addAugmentation(FlowStatisticsData.class,new FlowStatisticsDataBuilder()
-                    .setFlowStatistics(new FlowStatisticsBuilder().build())
-                    .build())
-            .setBarrier(true)
-            .setMatch(new MatchBuilder()
-            .build())
-        ;
+    private List11 createList11() {
+        List11Builder builder = new List11Builder()
+            .setKey(LIST11_KEY)
+            .addAugmentation(List11SimpleAugment.class,new List11SimpleAugmentBuilder()
+                    .setAttrStr2("bad").build())
+            .setAttrStr("good");
         return builder.build();
     }
 
index 7143352c1f9c8ec625b4f29e93912d30db815414..9ad46bb99ff4bdd9070ffa79866659e1aaab4cb0 100644 (file)
@@ -11,39 +11,20 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 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.action.types.rev131112.action.action.PopMplsActionCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.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.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.BitFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -54,41 +35,36 @@ import com.google.common.collect.ImmutableSet;
 
 @SuppressWarnings("deprecation")
 public class FlagsSerializationTest extends AbstractDataServiceTest {
-
-    private static final String FLOW_ID = "1234";
-    private static final short TABLE_ID = (short)0;
-    private static final String NODE_ID = "node:1";
-
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
-    private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID));
-    private static final TableKey TABLE_KEY = new TableKey(TABLE_ID);
-
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
-            .child(Node.class, NODE_KEY).toInstance();
-
-    private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
-            NODE_INSTANCE_ID_BA.builder() //
-            .augmentation(FlowCapableNode.class)
-            .child(Table.class,TABLE_KEY)
-            .child(Flow.class, FLOW_KEY) //
+    private static final TopLevelListKey TLL_KEY = new TopLevelListKey("foo");
+    private static final List11Key LIST11_KEY = new List11Key(1234);
+    private static final List1Key LIST1_KEY = new List1Key("1");
+
+    private static final InstanceIdentifier<TopLevelList> TLL_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
+            .child(TopLevelList.class, TLL_KEY).toInstance();
+
+    private static final InstanceIdentifier<? extends DataObject> LIST11_INSTANCE_ID_BA = //
+            TLL_INSTANCE_ID_BA.builder() //
+            .augmentation(TllComplexAugment.class)
+            .child(List1.class,LIST1_KEY)
+            .child(List11.class, LIST11_KEY) //
             .toInstance();
-    private static final QName FLOW_FLAGS_QNAME = QName.create(Flow.QNAME, "flags");
+    private static final QName LIST11_FLAGS_QNAME = QName.create(List11.QNAME, "flags");
 
     @Test
     public void testIndirectGeneration() throws Exception {
 
-        FlowModFlags checkOverlapFlags = new FlowModFlags(true,false,false,false,false);
-        ImmutableSet<String> domCheckOverlapFlags = ImmutableSet.<String>of("CHECK_OVERLAP");
+        BitFlags checkOverlapFlags = new BitFlags(true,false,false,false,false);
+        ImmutableSet<String> domCheckOverlapFlags = ImmutableSet.<String>of("FLAG_FIVE");
         testFlags(checkOverlapFlags,domCheckOverlapFlags);
 
 
 
-        FlowModFlags allFalseFlags = new FlowModFlags(false,false,false,false,false);
+        BitFlags allFalseFlags = new BitFlags(false,false,false,false,false);
         ImmutableSet<String> domAllFalseFlags = ImmutableSet.<String>of();
         testFlags(allFalseFlags,domAllFalseFlags);
 
-        FlowModFlags allTrueFlags = new FlowModFlags(true,true,true,true,true);
-        ImmutableSet<String> domAllTrueFlags = ImmutableSet.<String>of("CHECK_OVERLAP","NO_BYT_COUNTS", "NO_PKT_COUNTS", "RESET_COUNTS", "SEND_FLOW_REM");
+        BitFlags allTrueFlags = new BitFlags(true,true,true,true,true);
+        ImmutableSet<String> domAllTrueFlags = ImmutableSet.<String>of("FLAG_ONE","FLAG_TWO","FLAG_THREE","FLAG_FOUR","FLAG_FIVE");
         testFlags(allTrueFlags,domAllTrueFlags);
 
         testFlags(null,null);
@@ -97,14 +73,14 @@ public class FlagsSerializationTest extends AbstractDataServiceTest {
 
     }
 
-    private void testFlags(final FlowModFlags flagsToTest, final ImmutableSet<String> domFlags) throws Exception {
-        Flow flow = createFlow(flagsToTest);
-        assertNotNull(flow);
+    private void testFlags(final BitFlags flagsToTest, final ImmutableSet<String> domFlags) throws Exception {
+        List11 list11 = createList11(flagsToTest);
+        assertNotNull(list11);
 
-        CompositeNode domFlow = biDataService.readConfigurationData(mappingService.toDataDom(FLOW_INSTANCE_ID_BA));
+        CompositeNode domList11 = biDataService.readConfigurationData(mappingService.toDataDom(LIST11_INSTANCE_ID_BA));
 
-        assertNotNull(domFlow);
-        org.opendaylight.yangtools.yang.data.api.Node<?> readedFlags = domFlow.getFirstSimpleByName(FLOW_FLAGS_QNAME);
+        assertNotNull(domList11);
+        org.opendaylight.yangtools.yang.data.api.Node<?> readedFlags = domList11.getFirstSimpleByName(LIST11_FLAGS_QNAME);
 
         if(domFlags != null) {
             assertNotNull(readedFlags);
@@ -112,55 +88,30 @@ public class FlagsSerializationTest extends AbstractDataServiceTest {
         } else {
             assertNull(readedFlags);
         }
-        assertEquals(flagsToTest, flow.getFlags());
+        assertEquals(flagsToTest, list11.getFlags());
 
         DataModificationTransaction transaction = baDataService.beginTransaction();
-        transaction.removeConfigurationData(FLOW_INSTANCE_ID_BA);
+        transaction.removeConfigurationData(LIST11_INSTANCE_ID_BA);
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
     }
 
-    private Flow createFlow(final FlowModFlags flagsToTest) throws Exception {
+    private List11 createList11(final BitFlags flagsToTest) throws Exception {
 
         DataModificationTransaction modification = baDataService.beginTransaction();
 
-        FlowBuilder flow = new FlowBuilder();
-        MatchBuilder match = new MatchBuilder();
-        VlanMatchBuilder vlanBuilder = new VlanMatchBuilder();
-        VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
-        VlanId vlanId = new VlanId(10);
-        vlanBuilder.setVlanId(vlanIdBuilder.setVlanId(vlanId).build());
-        match.setVlanMatch(vlanBuilder.build());
-
-        flow.setKey(FLOW_KEY);
-        flow.setMatch(match.build());
-
-        flow.setFlags(flagsToTest);
-
-        InstructionsBuilder instructions = new InstructionsBuilder();
-        InstructionBuilder instruction = new InstructionBuilder();
-
-        instruction.setOrder(10);
-        ApplyActionsBuilder applyActions = new ApplyActionsBuilder();
-        List<Action> actionList = new ArrayList<>();
-        PopMplsActionBuilder popMplsAction = new PopMplsActionBuilder();
-        popMplsAction.setEthernetType(34);
-        actionList.add(new ActionBuilder().setAction(new PopMplsActionCaseBuilder().setPopMplsAction(popMplsAction.build()).build()).setOrder(10).build());
-
-        applyActions.setAction(actionList );
-
-        instruction.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActions.build()).build());
+        List11Builder list11b = new List11Builder();
 
+        list11b.setKey(LIST11_KEY);
+        list11b.setAttrStr("list:1:1");
 
-        List<Instruction> instructionList = Collections.<Instruction>singletonList(instruction.build());
-        instructions.setInstruction(instructionList );
+        list11b.setFlags(flagsToTest);
 
-        flow.setInstructions(instructions.build());
-        modification.putConfigurationData(FLOW_INSTANCE_ID_BA, flow.build());
+        modification.putConfigurationData(LIST11_INSTANCE_ID_BA, list11b.build());
         RpcResult<TransactionStatus> ret = modification.commit().get();
         assertNotNull(ret);
         assertEquals(TransactionStatus.COMMITED, ret.getResult());
-        return (Flow) baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA);
+        return (List11) baDataService.readConfigurationData(LIST11_INSTANCE_ID_BA);
     }
 }
index 767ccaade304a711b7c54f4c958a8b4c2ea5ae5b..9bf6c4d291897314067ed4ab7fcbec71412e5d95 100644 (file)
@@ -23,19 +23,18 @@ 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.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.NestedListSimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.NestedListSimpleAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -47,35 +46,35 @@ import com.google.common.util.concurrent.SettableFuture;
 @SuppressWarnings("deprecation")
 public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener {
 
-    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
-    private static final String NODE_ID = "openflow:1";
+    private static final QName TLL_NAME_QNAME = QName.create(TopLevelList.QNAME, "name");
+    private static final String TLL_NAME = "foo";
 
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+    private static final TopLevelListKey TLL_KEY = new TopLevelListKey(TLL_NAME);
 
-    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
-            NODE_ID);
+    private static final Map<QName, Object> TLL_KEY_BI = Collections.<QName, Object> singletonMap(TLL_NAME_QNAME,
+            TLL_NAME);
 
-    private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+    private static final InstanceIdentifier<Top> TOP_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
             .toInstance();
 
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = //
-            NODES_INSTANCE_ID_BA.builder() //
-            .child(Node.class, NODE_KEY).toInstance();
+    private static final InstanceIdentifier<TopLevelList> TLL_INSTANCE_ID_BA = //
+            TOP_INSTANCE_ID_BA.builder() //
+            .child(TopLevelList.class, TLL_KEY).toInstance();
 
-    private static final InstanceIdentifier<FlowCapableNode> ALL_FLOW_CAPABLE_NODES = //
-            NODES_INSTANCE_ID_BA.builder() //
-            .child(Node.class) //
-            .augmentation(FlowCapableNode.class) //
+    private static final InstanceIdentifier<TllComplexAugment> ALL_TCA = //
+            TOP_INSTANCE_ID_BA.builder() //
+            .child(TopLevelList.class) //
+            .augmentation(TllComplexAugment.class) //
             .build();
 
-    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier NODE_INSTANCE_ID_BI = //
+    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier TLL_INSTANCE_ID_BI = //
     org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder() //
-            .node(Nodes.QNAME) //
-            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .node(Top.QNAME) //
+            .nodeWithKey(TopLevelList.QNAME, TLL_KEY_BI) //
             .toInstance();
-    private static final InstanceIdentifier<FlowCapableNode> FLOW_AUGMENTATION_PATH =
-            NODE_INSTANCE_ID_BA.builder() //
-            .augmentation(FlowCapableNode.class) //
+    private static final InstanceIdentifier<TllComplexAugment> TCA_AUGMENTATION_PATH =
+            TLL_INSTANCE_ID_BA.builder() //
+            .augmentation(TllComplexAugment.class) //
             .build();
 
     private SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> lastReceivedChangeEvent;
@@ -89,32 +88,28 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
     @Ignore
     public void putNodeAndAugmentation() throws Exception {
         lastReceivedChangeEvent = SettableFuture.create();
-        baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this);
+        baDataService.registerDataChangeListener(ALL_TCA, this);
 
 
-        NodeBuilder nodeBuilder = new NodeBuilder();
-        nodeBuilder.setId(new NodeId(NODE_ID));
-        nodeBuilder.setKey(NODE_KEY);
+        TopLevelListBuilder nodeBuilder = new TopLevelListBuilder();
+        nodeBuilder.setKey(TLL_KEY);
         DataModificationTransaction baseTransaction = baDataService.beginTransaction();
-        baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
+        baseTransaction.putOperationalData(TLL_INSTANCE_ID_BA, nodeBuilder.build());
         RpcResult<TransactionStatus> result = baseTransaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
-        assertNotNull(node);
-        assertEquals(NODE_KEY, node.getKey());
-
-        FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
-        fnub.setHardware("Hardware Foo");
-        fnub.setManufacturer("Manufacturer Foo");
-        fnub.setSerialNumber("Serial Foo");
-        fnub.setDescription("Description Foo");
-        fnub.setSoftware("JUnit emulated");
-        FlowCapableNode fnu = fnub.build();
-        InstanceIdentifier<FlowCapableNode> augmentIdentifier = NODE_INSTANCE_ID_BA
-                .augmentation(FlowCapableNode.class);
+        TopLevelList tll = (TopLevelList) baDataService.readOperationalData(TLL_INSTANCE_ID_BA);
+        assertNotNull(tll);
+        assertEquals(TLL_KEY, tll.getKey());
+
+        TllComplexAugmentBuilder tcab = new TllComplexAugmentBuilder();
+        tcab.setAttrStr1("FooFoo");
+        tcab.setAttrStr2("BarBar");
+        TllComplexAugment tca = tcab.build();
+        InstanceIdentifier<TreeComplexUsesAugment> augmentIdentifier = TLL_INSTANCE_ID_BA
+                .augmentation(TreeComplexUsesAugment.class);
         DataModificationTransaction augmentedTransaction = baDataService.beginTransaction();
-        augmentedTransaction.putOperationalData(augmentIdentifier, fnu);
+        augmentedTransaction.putOperationalData(augmentIdentifier, tca);
 
 
         lastReceivedChangeEvent = SettableFuture.create();
@@ -123,102 +118,98 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
 
         DataChangeEvent<InstanceIdentifier<?>, DataObject> potential = lastReceivedChangeEvent.get(1000,TimeUnit.MILLISECONDS);
         assertNotNull(potential);
-        assertTrue(potential.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH));
+        assertTrue(potential.getCreatedOperationalData().containsKey(TCA_AUGMENTATION_PATH));
 
         lastReceivedChangeEvent = SettableFuture.create();
 
-        Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
-        assertNotNull(node);
-        assertEquals(NODE_KEY, augmentedNode.getKey());
+        TopLevelList augmentedTll = (TopLevelList) baDataService.readOperationalData(TLL_INSTANCE_ID_BA);
+        assertNotNull(tll);
+        assertEquals(TLL_KEY, augmentedTll.getKey());
         System.out.println("Before assertion");
-        assertNotNull(augmentedNode.getAugmentation(FlowCapableNode.class));
-        FlowCapableNode readedAugmentation = augmentedNode.getAugmentation(FlowCapableNode.class);
-        assertEquals(fnu.getDescription(), readedAugmentation.getDescription());
-        assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
-        testNodeRemove();
-        assertTrue(lastReceivedChangeEvent.get(1000,TimeUnit.MILLISECONDS).getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH));
+        assertNotNull(augmentedTll.getAugmentation(TllComplexAugment.class));
+        TllComplexAugment readedAugmentation = augmentedTll.getAugmentation(TllComplexAugment.class);
+        assertEquals(tca.getAttrStr2(), readedAugmentation.getAttrStr2());
+        assertBindingIndependentVersion(TLL_INSTANCE_ID_BI);
+        testTllRemove();
+        assertTrue(lastReceivedChangeEvent.get(1000,TimeUnit.MILLISECONDS).getRemovedOperationalData().contains(TCA_AUGMENTATION_PATH));
     }
 
     @Test
     @Ignore
     public void putNodeWithAugmentation() throws Exception {
         lastReceivedChangeEvent = SettableFuture.create();
-        baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this);
-
-        NodeBuilder nodeBuilder = new NodeBuilder();
-        nodeBuilder.setId(new NodeId(NODE_ID));
-        nodeBuilder.setKey(NODE_KEY);
-        FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
-        fnub.setHardware("Hardware Foo");
-        fnub.setManufacturer("Manufacturer Foo");
-        fnub.setSerialNumber("Serial Foo");
-        fnub.setDescription("Description Foo");
-        fnub.setSoftware("JUnit emulated");
-        FlowCapableNode fnu = fnub.build();
-
-        nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
+        baDataService.registerDataChangeListener(ALL_TCA, this);
+
+        TopLevelListBuilder nodeBuilder = new TopLevelListBuilder();
+        nodeBuilder.setKey(TLL_KEY);
+        TllComplexAugmentBuilder tcab = new TllComplexAugmentBuilder();
+        tcab.setAttrStr1("FooFoo");
+        tcab.setAttrStr2("BarBar");
+        TllComplexAugment tca = tcab.build();
+
+        nodeBuilder.addAugmentation(TreeComplexUsesAugment.class, tca);
         DataModificationTransaction baseTransaction = baDataService.beginTransaction();
-        baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
+        baseTransaction.putOperationalData(TLL_INSTANCE_ID_BA, nodeBuilder.build());
         RpcResult<TransactionStatus> result = baseTransaction.commit().get();
 
 
         DataChangeEvent<InstanceIdentifier<?>, DataObject> potential = lastReceivedChangeEvent.get(1000,TimeUnit.MILLISECONDS);
         assertNotNull(potential);
-        assertTrue(potential.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH));
+        assertTrue(potential.getCreatedOperationalData().containsKey(TCA_AUGMENTATION_PATH));
         lastReceivedChangeEvent = SettableFuture.create();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        FlowCapableNode readedAugmentation = (FlowCapableNode) baDataService.readOperationalData(
-                NODE_INSTANCE_ID_BA.augmentation(FlowCapableNode.class));
+        TllComplexAugment readedAugmentation = (TllComplexAugment) baDataService.readOperationalData(
+                TLL_INSTANCE_ID_BA.augmentation(TllComplexAugment.class));
         assertNotNull(readedAugmentation);
 
-        assertEquals(fnu.getHardware(), readedAugmentation.getHardware());
+        assertEquals(tca.getAttrStr1(), readedAugmentation.getAttrStr1());
 
         testPutNodeConnectorWithAugmentation();
         lastReceivedChangeEvent = SettableFuture.create();
-        testNodeRemove();
+        testTllRemove();
 
-        assertTrue(lastReceivedChangeEvent.get(1000,TimeUnit.MILLISECONDS).getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH));
+        assertTrue(lastReceivedChangeEvent.get(1000,TimeUnit.MILLISECONDS).getRemovedOperationalData().contains(TCA_AUGMENTATION_PATH));
     }
 
     private void testPutNodeConnectorWithAugmentation() throws Exception {
-        NodeConnectorKey ncKey = new NodeConnectorKey(new NodeConnectorId("test:0:0"));
-        InstanceIdentifier<NodeConnector> ncPath = NODE_INSTANCE_ID_BA
-                .child(NodeConnector.class, ncKey);
-        InstanceIdentifier<FlowCapableNodeConnector> ncAugmentPath = ncPath
-                .augmentation(FlowCapableNodeConnector.class);
+        NestedListKey ncKey = new NestedListKey("test:0:0");
+        InstanceIdentifier<NestedList> ncPath = TLL_INSTANCE_ID_BA
+                .child(NestedList.class, ncKey);
+        InstanceIdentifier<NestedListSimpleAugment> ncAugmentPath = ncPath
+                .augmentation(NestedListSimpleAugment.class);
 
-        NodeConnectorBuilder nc = new NodeConnectorBuilder();
+        NestedListBuilder nc = new NestedListBuilder();
         nc.setKey(ncKey);
 
-        FlowCapableNodeConnectorBuilder fncb = new FlowCapableNodeConnectorBuilder();
-        fncb.setName("Baz");
-        nc.addAugmentation(FlowCapableNodeConnector.class, fncb.build());
+        NestedListSimpleAugmentBuilder fncb = new NestedListSimpleAugmentBuilder();
+        fncb.setType("Baz");
+        nc.addAugmentation(NestedListSimpleAugment.class, fncb.build());
 
         DataModificationTransaction baseTransaction = baDataService.beginTransaction();
         baseTransaction.putOperationalData(ncPath, nc.build());
         RpcResult<TransactionStatus> result = baseTransaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        FlowCapableNodeConnector readedAugmentation = (FlowCapableNodeConnector) baDataService
+        NestedListSimpleAugment readedAugmentation = (NestedListSimpleAugment) baDataService
                 .readOperationalData(ncAugmentPath);
         assertNotNull(readedAugmentation);
-        assertEquals(fncb.getName(), readedAugmentation.getName());
+        assertEquals(fncb.getType(), readedAugmentation.getType());
     }
 
-    private void testNodeRemove() throws Exception {
+    private void testTllRemove() throws Exception {
         DataModificationTransaction transaction = baDataService.beginTransaction();
-        transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
+        transaction.removeOperationalData(TLL_INSTANCE_ID_BA);
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
-        assertNull(node);
+        TopLevelList tll = (TopLevelList) baDataService.readOperationalData(TLL_INSTANCE_ID_BA);
+        assertNull(tll);
     }
 
-    private void assertBindingIndependentVersion(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier nodeId) {
-        CompositeNode node = biDataService.readOperationalData(nodeId);
-        assertNotNull(node);
+    private void assertBindingIndependentVersion(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier tllId) {
+        CompositeNode tll = biDataService.readOperationalData(tllId);
+        assertNotNull(tll);
     }
 
     @Override
index b09ba39a65e120f20c51801f2a699552f91132eb..0f9051d41c650ebddd0d2b02b71d39f3ae5e5b8c 100644 (file)
@@ -18,13 +18,13 @@ 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.augment.rev140709.complex.from.grouping.ContainerWithUsesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -34,17 +34,17 @@ import com.google.common.util.concurrent.SettableFuture;
 @SuppressWarnings("deprecation")
 public class WriteParentListenAugmentTest extends AbstractDataServiceTest {
 
-    private static final String NODE_ID = "node:1";
+    private static final String TLL_NAME = "foo";
 
-    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 TopLevelListKey TLL_KEY = new TopLevelListKey(TLL_NAME);
+    private static final InstanceIdentifier<TopLevelList> TLL_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
+            .child(TopLevelList.class, TLL_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<TreeComplexUsesAugment> AUGMENT_WILDCARDED_PATH = InstanceIdentifier
+            .builder(Top.class).child(TopLevelList.class).augmentation(TreeComplexUsesAugment.class).toInstance();
 
-    private static final InstanceIdentifier<FlowCapableNode> AUGMENT_NODE_PATH = InstanceIdentifier
-            .builder(Nodes.class).child(Node.class, NODE_KEY).augmentation(FlowCapableNode.class).toInstance();
+    private static final InstanceIdentifier<TreeComplexUsesAugment> AUGMENT_TLL_PATH = InstanceIdentifier
+            .builder(Top.class).child(TopLevelList.class, TLL_KEY).augmentation(TreeComplexUsesAugment.class).toInstance();
 
     @Test
     public void writeNodeListenAugment() throws Exception {
@@ -62,29 +62,29 @@ public class WriteParentListenAugmentTest extends AbstractDataServiceTest {
 
         DataModificationTransaction modification = baDataService.beginTransaction();
 
-        Node node = new NodeBuilder() //
-                .setKey(NODE_KEY) //
-                .addAugmentation(FlowCapableNode.class, flowCapableNode("one")).build();
-        modification.putOperationalData(NODE_INSTANCE_ID_BA, node);
+        TopLevelList tll = new TopLevelListBuilder() //
+                .setKey(TLL_KEY) //
+                .addAugmentation(TreeComplexUsesAugment.class, treeComplexUsesAugment("one")).build();
+        modification.putOperationalData(TLL_INSTANCE_ID_BA, tll);
         modification.commit().get();
 
         DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedEvent = event.get(1000, TimeUnit.MILLISECONDS);
-        assertTrue(receivedEvent.getCreatedOperationalData().containsKey(AUGMENT_NODE_PATH));
+        assertTrue(receivedEvent.getCreatedOperationalData().containsKey(AUGMENT_TLL_PATH));
 
         dclRegistration.close();
 
         DataModificationTransaction mod2 = baDataService.beginTransaction();
-        mod2.putOperationalData(AUGMENT_NODE_PATH, flowCapableNode("two"));
+        mod2.putOperationalData(AUGMENT_TLL_PATH, treeComplexUsesAugment("two"));
         mod2.commit().get();
 
-        FlowCapableNode readedAug = (FlowCapableNode) baDataService.readOperationalData(AUGMENT_NODE_PATH);
-        assertEquals("two", readedAug.getDescription());
+        TreeComplexUsesAugment readedAug = (TreeComplexUsesAugment) baDataService.readOperationalData(AUGMENT_TLL_PATH);
+        assertEquals("two", readedAug.getContainerWithUses().getLeafFromGrouping());
 
     }
 
-    private FlowCapableNode flowCapableNode(final String description) {
-        return new FlowCapableNodeBuilder() //
-                .setDescription(description) //
+    private TreeComplexUsesAugment treeComplexUsesAugment(final String value) {
+        return new TreeComplexUsesAugmentBuilder() //
+                .setContainerWithUses(new ContainerWithUsesBuilder().setLeafFromGrouping(value).build()) //
                 .build();
     }
 }
\ No newline at end of file
index ad02d9a6f6df31239c108352294a595452d43f7e..7941f4d4aee1884e462fbc7e690ce66b4752e419 100644 (file)
@@ -16,24 +16,16 @@ import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 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.FlowId;
-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.TableBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-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.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -43,23 +35,23 @@ import com.google.common.collect.ImmutableList;
 @SuppressWarnings("deprecation")
 public class WriteParentReadChildTest extends AbstractDataServiceTest {
 
-    private static final String FLOW_ID = "1234";
-    private static final short TABLE_ID = (short) 0;
-    private static final String NODE_ID = "node:1";
+    private static final int LIST11_ID = 1234;
+    private static final String LIST1_NAME = "bar";
+    private static final String TLL_NAME = "foo";
 
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
-    private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID));
-    private static final TableKey TABLE_KEY = new TableKey(TABLE_ID);
+    private static final TopLevelListKey TLL_KEY = new TopLevelListKey(TLL_NAME);
+    private static final List11Key LIST11_KEY = new List11Key(LIST11_ID);
+    private static final List1Key LIST1_KEY = new List1Key(LIST1_NAME);
 
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
-            .child(Node.class, NODE_KEY).toInstance();
+    private static final InstanceIdentifier<TopLevelList> TLL_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
+            .child(TopLevelList.class, TLL_KEY).toInstance();
 
-    private static final InstanceIdentifier<Table> TABLE_INSTANCE_ID_BA = //
-            NODE_INSTANCE_ID_BA.builder() //
-            .augmentation(FlowCapableNode.class).child(Table.class, TABLE_KEY).build();
+    private static final InstanceIdentifier<List1> LIST1_INSTANCE_ID_BA = //
+            TLL_INSTANCE_ID_BA.builder() //
+            .augmentation(TllComplexAugment.class).child(List1.class, LIST1_KEY).build();
 
-    private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
-            TABLE_INSTANCE_ID_BA.child(Flow.class, FLOW_KEY);
+    private static final InstanceIdentifier<? extends DataObject> LIST11_INSTANCE_ID_BA = //
+            LIST1_INSTANCE_ID_BA.child(List11.class, LIST11_KEY);
     /**
      *
      * The scenario tests writing parent node, which also contains child items
@@ -70,43 +62,33 @@ public class WriteParentReadChildTest extends AbstractDataServiceTest {
      * @throws Exception
      */
     @Test
-    public void writeTableReadFlow() throws Exception {
+    public void writeParentReadChild() throws Exception {
 
         DataModificationTransaction modification = baDataService.beginTransaction();
 
-        Flow flow = new FlowBuilder() //
-                .setKey(FLOW_KEY) //
-                .setMatch(new MatchBuilder() //
-                        .setVlanMatch(new VlanMatchBuilder() //
-                                .setVlanId(new VlanIdBuilder() //
-                                        .setVlanId(new VlanId(10)) //
-                                        .build()) //
-                                .build()) //
-                        .build()) //
-                        .setInstructions(new InstructionsBuilder() //
-                            .setInstruction(ImmutableList.<Instruction>builder() //
-                                    .build()) //
-                        .build()) //
+        List11 list11 = new List11Builder() //
+                .setKey(LIST11_KEY) //
+                .setAttrStr("primary")
                 .build();
 
-        Table table = new TableBuilder()
-            .setKey(TABLE_KEY)
-            .setFlow(ImmutableList.of(flow))
+        List1 list1 = new List1Builder()
+            .setKey(LIST1_KEY)
+            .setList11(ImmutableList.of(list11))
         .build();
 
-        modification.putConfigurationData(TABLE_INSTANCE_ID_BA, table);
+        modification.putConfigurationData(LIST1_INSTANCE_ID_BA, list1);
         RpcResult<TransactionStatus> ret = modification.commit().get();
         assertNotNull(ret);
         assertEquals(TransactionStatus.COMMITED, ret.getResult());
 
-        DataObject readedTable = baDataService.readConfigurationData(TABLE_INSTANCE_ID_BA);
-        assertNotNull("Readed table should not be nul.", readedTable);
-        assertTrue(readedTable instanceof Table);
+        DataObject readList1 = baDataService.readConfigurationData(LIST1_INSTANCE_ID_BA);
+        assertNotNull("Readed table should not be nul.", readList1);
+        assertTrue(readList1 instanceof List1);
 
-        DataObject readedFlow = baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA);
-        assertNotNull("Readed flow should not be null.",readedFlow);
-        assertTrue(readedFlow instanceof Flow);
-        assertEquals(flow, readedFlow);
+        DataObject readList11 = baDataService.readConfigurationData(LIST11_INSTANCE_ID_BA);
+        assertNotNull("Readed flow should not be null.",readList11);
+        assertTrue(readList11 instanceof List11);
+        assertEquals(list11, readList11);
 
     }
 }
index 481a7ddfa2c42863b3cb17b17826d0a5748fa778..48027114d75997b4e99a85d7fc655b668393e3d8 100644 (file)
@@ -17,30 +17,37 @@ import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 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.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
-// FIXME: Migrate to use new Data Broker APIs
+/**
+ * FIXME: Migrate to use new Data Broker APIs
+ */
 @SuppressWarnings("deprecation")
 public class BrokerIntegrationTest extends AbstractDataServiceTest {
 
+    private static final TopLevelListKey TLL_FOO_KEY = new TopLevelListKey("foo");
+    private static final TopLevelListKey TLL_BAR_KEY = new TopLevelListKey("bar");
+    private static final TopLevelListKey TLL_BAZ_KEY = new TopLevelListKey("baz");
+    private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.builder(Top.class).build();
+    private static final InstanceIdentifier<TopLevelList> FOO_PATH = TOP_PATH.child(TopLevelList.class, TLL_FOO_KEY);
+    private static final InstanceIdentifier<TopLevelList> BAR_PATH = TOP_PATH.child(TopLevelList.class, TLL_BAR_KEY);
+    private static final InstanceIdentifier<TopLevelList> BAZ_PATH = TOP_PATH.child(TopLevelList.class, TLL_BAZ_KEY);
+
     @Test
     public void simpleModifyOperation() throws Exception {
 
-        NodeRef node1 = createNodeRef("0");
-        DataObject node = baDataService.readConfigurationData(node1.getValue());
-        assertNull(node);
-        Node nodeData1 = createNode("0");
+        DataObject tllFoo = baDataService.readConfigurationData(FOO_PATH);
+        assertNull(tllFoo);
+        TopLevelList tllFooData = createTll(TLL_FOO_KEY);
 
         DataModificationTransaction transaction = baDataService.beginTransaction();
-        transaction.putConfigurationData(node1.getValue(), nodeData1);
+        transaction.putConfigurationData(FOO_PATH, tllFooData);
         Future<RpcResult<TransactionStatus>> commitResult = transaction.commit();
         assertNotNull(commitResult);
 
@@ -50,29 +57,26 @@ public class BrokerIntegrationTest extends AbstractDataServiceTest {
         assertNotNull(result.getResult());
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        Node readedData = (Node) baDataService.readConfigurationData(node1.getValue());
+        TopLevelList readedData = (TopLevelList) baDataService.readConfigurationData(FOO_PATH);
         assertNotNull(readedData);
-        assertEquals(nodeData1.getKey(), readedData.getKey());
+        assertEquals(tllFooData.getKey(), readedData.getKey());
 
-        NodeRef nodeFoo = createNodeRef("foo");
-        NodeRef nodeBar = createNodeRef("bar");
-        Node nodeFooData = createNode("foo");
-        Node nodeBarData = createNode("bar");
+        TopLevelList nodeBarData = createTll(TLL_BAR_KEY);
+        TopLevelList nodeBazData = createTll(TLL_BAZ_KEY);
 
         DataModificationTransaction insertMoreTr = baDataService.beginTransaction();
-        insertMoreTr.putConfigurationData(nodeFoo.getValue(), nodeFooData);
-        insertMoreTr.putConfigurationData(nodeBar.getValue(), nodeBarData);
+        insertMoreTr.putConfigurationData(BAR_PATH, nodeBarData);
+        insertMoreTr.putConfigurationData(BAZ_PATH, nodeBazData);
         RpcResult<TransactionStatus> result2 = insertMoreTr.commit().get();
 
         assertNotNull(result2);
         assertNotNull(result2.getResult());
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        Nodes allNodes = (Nodes) baDataService.readConfigurationData(InstanceIdentifier.builder(Nodes.class)
-                .toInstance());
-        assertNotNull(allNodes);
-        assertNotNull(allNodes.getNode());
-        assertEquals(3, allNodes.getNode().size());
+        Top top = (Top) baDataService.readConfigurationData(TOP_PATH);
+        assertNotNull(top);
+        assertNotNull(top.getTopLevelList());
+        assertEquals(3, top.getTopLevelList().size());
 
         /**
          * We create transaction no 2
@@ -85,7 +89,7 @@ public class BrokerIntegrationTest extends AbstractDataServiceTest {
          * We remove node 1
          *
          */
-        removalTransaction.removeConfigurationData(node1.getValue());
+        removalTransaction.removeConfigurationData(BAR_PATH);
 
         /**
          * We commit transaction
@@ -99,21 +103,13 @@ public class BrokerIntegrationTest extends AbstractDataServiceTest {
         assertNotNull(result3.getResult());
         assertEquals(TransactionStatus.COMMITED, result2.getResult());
 
-        DataObject readedData2 = baDataService.readConfigurationData(node1.getValue());
+        DataObject readedData2 = baDataService.readConfigurationData(BAR_PATH);
         assertNull(readedData2);
     }
 
-    private static NodeRef createNodeRef(final String string) {
-        NodeKey key = new NodeKey(new NodeId(string));
-        InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
-                .toInstance();
-        return new NodeRef(path);
-    }
-
-    private static Node createNode(final String string) {
-        NodeBuilder ret = new NodeBuilder();
-        ret.setId(new NodeId(string));
-        ret.setKey(new NodeKey(ret.getId()));
+    private static TopLevelList createTll(final TopLevelListKey key) {
+        TopLevelListBuilder ret = new TopLevelListBuilder();
+        ret.setKey(key);
         return ret.build();
     }
 }
index a3b0819501c57ffdcf3764c243a20e680d8d9ecf..25b159b43b297eaeee8755c50688e5d0a2ff9aab 100644 (file)
@@ -11,9 +11,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
@@ -23,34 +21,17 @@ 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.test.AbstractDataServiceTest;
 import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpVersion;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecNwTtlCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtl;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtlBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.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.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List12Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List12Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -59,83 +40,79 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.SettableFuture;
 
-// FIXME: Migrate to use new Data Broker APIs
+/**
+ * FIXME: Migrate to use new Data Broker APIs
+ */
 @SuppressWarnings("deprecation")
 public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest {
 
-    private static final Logger LOG = LoggerFactory.getLogger(ChangeOriginatedInDomBrokerTest.class);
-
-    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
-    private static final QName FLOW_ID_QNAME = QName.create(Flow.QNAME, "id");
-    private static final QName TABLE_ID_QNAME = QName.create(Table.QNAME, "id");
+    protected static final Logger LOG = LoggerFactory.getLogger(ChangeOriginatedInDomBrokerTest.class);
 
-    private static final String NODE_ID = "node:1";
-    private static final FlowId FLOW_ID = new FlowId("1234");
-    private static final Short TABLE_ID = Short.valueOf((short) 0);
+    private static final QName TLL_NAME_QNAME = QName.create(TopLevelList.QNAME, "name");
+    private static final QName LIST1_ATTR_STR_QNAME = QName.create(List1.QNAME, "attr-str");
 
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
-    private static final FlowKey FLOW_KEY = new FlowKey(FLOW_ID);
+    private static final String TLL_NAME = "1";
+    private static final int LIST11_ATTR_INT = 1234;
+    private static final String LIST1_ATTR_STR = "foo:foo";
 
-    private final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> modificationCapture = SettableFuture.create();
+    private static final TopLevelListKey TLL_KEY = new TopLevelListKey(TLL_NAME);
+    private static final List1Key LIST1_KEY = new List1Key(LIST1_ATTR_STR);
+    private static final List11Key LIST11_KEY = new List11Key(LIST11_ATTR_INT);
 
-    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
-            NODE_ID);
+    protected final SettableFuture<DataChangeEvent<InstanceIdentifier<?>, DataObject>> modificationCapture = SettableFuture.create();
 
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
-            .child(Node.class, NODE_KEY).toInstance();
+    private static final Map<QName, Object> TLL_KEY_BI = Collections.<QName, Object> singletonMap(TLL_NAME_QNAME,
+            TLL_NAME);
 
-    private static final Map<QName, Object> FLOW_KEY_BI = //
-    ImmutableMap.<QName, Object> of(FLOW_ID_QNAME, FLOW_ID.getValue());
+    private static final InstanceIdentifier<TopLevelList> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
+            .child(TopLevelList.class, TLL_KEY).toInstance();
 
-    private static final Map<QName, Object> TABLE_KEY_BI = //
-    ImmutableMap.<QName, Object> of(TABLE_ID_QNAME, TABLE_ID);;
+    private static final Map<QName, Object> LIST1_KEY_BI = //
+    ImmutableMap.<QName, Object> of(LIST1_ATTR_STR_QNAME, LIST1_ATTR_STR);;
 
-    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier FLOW_INSTANCE_ID_BI = //
+    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier LIST1_INSTANCE_ID_BI = //
     org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder() //
-            .node(Nodes.QNAME) //
-            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
-            .nodeWithKey(Table.QNAME, TABLE_KEY_BI) //
-            .nodeWithKey(Flow.QNAME, FLOW_KEY_BI) //
+            .node(Top.QNAME) //
+            .nodeWithKey(TopLevelList.QNAME, TLL_KEY_BI) //
+            .nodeWithKey(List1.QNAME, LIST1_KEY_BI) //
             .toInstance();
-    private static final TableKey TABLE_KEY_BA = new TableKey((short) 0);
 
-    private static final InstanceIdentifier<Flow> FLOWS_PATH_BA = //
+    private static final InstanceIdentifier<List1> LIST1_PATH_BA = //
             NODE_INSTANCE_ID_BA.builder() //
-            .augmentation(FlowCapableNode.class) //
-            .child(Table.class, TABLE_KEY_BA) //
-            .child(Flow.class) //
+            .augmentation(TllComplexAugment.class) //
+            .child(List1.class, LIST1_KEY) //
             .toInstance();
 
-    private static final InstanceIdentifier<Flow> FLOW_INSTANCE_ID_BA = //
-    FLOWS_PATH_BA.firstIdentifierOf(Table.class).child(Flow.class, FLOW_KEY);
-
     @Test
     public void simpleModifyOperation() throws Exception {
 
-        assertNull(biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI));
+        assertNull(biDataService.readConfigurationData(LIST1_INSTANCE_ID_BI));
 
         registerChangeListener();
 
-        CompositeNode domflow = createTestFlow();
+        CompositeNode domflow = createTestList1();
         DataModificationTransaction biTransaction = biDataService.beginTransaction();
-        biTransaction.putConfigurationData(FLOW_INSTANCE_ID_BI, domflow);
+        biTransaction.putConfigurationData(LIST1_INSTANCE_ID_BI, domflow);
         RpcResult<TransactionStatus> biResult = biTransaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, biResult.getResult());
         DataChangeEvent<InstanceIdentifier<?>, DataObject> event = modificationCapture.get(1000,TimeUnit.MILLISECONDS);
         assertNotNull(event);
         LOG.info("Created Configuration :{}",event.getCreatedConfigurationData());
-        Flow flow = (Flow) event.getCreatedConfigurationData().get(FLOW_INSTANCE_ID_BA);
-        assertNotNull(flow);
-        assertNotNull(flow.getMatch());
+        List1 list1 = (List1) event.getCreatedConfigurationData().get(LIST1_PATH_BA);
+        assertNotNull(list1);
+        assertNotNull(list1.getAttrStr());
+        assertNotNull(list1.getList11());
+        assertNotNull(list1.getList12());
         assertEquals(TransactionStatus.COMMITED, biResult.getResult());
 
     }
 
     private void registerChangeListener() {
-        baDataService.registerDataChangeListener(FLOWS_PATH_BA, new DataChangeListener() {
+        baDataService.registerDataChangeListener(LIST1_PATH_BA, new DataChangeListener() {
 
             @Override
             public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
@@ -145,61 +122,18 @@ public class ChangeOriginatedInDomBrokerTest extends AbstractDataServiceTest {
         });
     }
 
-    private CompositeNode createTestFlow() {
-        FlowBuilder flow = new FlowBuilder();
-        flow.setKey(FLOW_KEY);
-        Short tableId = 0;
-        flow.setTableId(tableId);
-        MatchBuilder match = new MatchBuilder();
-        match.setIpMatch(new IpMatchBuilder().setIpProto(IpVersion.Ipv4).build());
-        Ipv4MatchBuilder ipv4Match = new Ipv4MatchBuilder();
-        // ipv4Match.setIpv4Destination(new Ipv4Prefix(cliInput.get(4)));
-        Ipv4Prefix prefix = new Ipv4Prefix("10.0.0.1/24");
-        ipv4Match.setIpv4Destination(prefix);
-        Ipv4Match i4m = ipv4Match.build();
-        match.setLayer3Match(i4m);
-        flow.setMatch(match.build());
-
-
-
-        // Create a drop action
-        /*
-         * Note: We are mishandling drop actions DropAction dropAction = new
-         * DropActionBuilder().build(); ActionBuilder ab = new ActionBuilder();
-         * ab.setAction(dropAction);
-         */
-
-        DecNwTtl decNwTtl = new DecNwTtlBuilder().build();
-        ActionBuilder ab = new ActionBuilder();
-        ActionKey actionKey = new ActionKey(0);
-        ab.setKey(actionKey );
-        ab.setAction(new DecNwTtlCaseBuilder().setDecNwTtl(decNwTtl).build());
-
-        // Add our drop action to a list
-        List<Action> actionList = new ArrayList<Action>();
-        actionList.add(ab.build());
-
-        // Create an Apply Action
-        ApplyActionsBuilder aab = new ApplyActionsBuilder();
-        aab.setAction(actionList);
-
-        // Wrap our Apply Action in an Instruction
-        InstructionBuilder ib = new InstructionBuilder();
-        ib.setOrder(0);
-        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
-
-        // Put our Instruction in a list of Instructions
-        InstructionsBuilder isb = new InstructionsBuilder();
-        List<Instruction> instructions = new ArrayList<Instruction>();
-        instructions.add(ib.build());
-        isb.setInstruction(instructions);
-
-        // Add our instructions to the flow
-        flow.setInstructions(isb.build());
-
-        flow.setPriority(2);
-        flow.setFlowName("Foo Name");
-        CompositeNode domFlow = mappingService.toDataDom(flow.build());
-        return domFlow;
+    private CompositeNode createTestList1() {
+        List1Builder l1b = new List1Builder();
+        List11Builder l11b = new List11Builder();
+        List12Builder l12b = new List12Builder();
+        l11b.setKey(LIST11_KEY);
+        l11b.setAttrStr("foo:foo:foo");
+        l12b.setKey(new List12Key(321));
+        l12b.setAttrStr("foo:foo:bar");
+        l1b.setKey(LIST1_KEY);
+        l1b.setList11(ImmutableList.of(l11b.build()));
+        l1b.setList12(ImmutableList.of(l12b.build()));
+        CompositeNode domList1 = mappingService.toDataDom(l1b.build());
+        return domList1;
     }
 }
index d87470a5e97c19496b1e65beaa97eefd81ad45b4..f199d71aa5a2fd61515ca67c78486488198a0faf 100644 (file)
@@ -7,10 +7,9 @@
  */
 package org.opendaylight.controller.sal.binding.test.connect.dom;
 
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
-import java.math.BigInteger;
 import java.util.Collections;
 import java.util.Map;
 
@@ -23,16 +22,16 @@ import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactor
 import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
-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.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.List11SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.TllComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.List1Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.aug.grouping.list1.List11Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.top.top.level.list.list1.list1._1.Cont;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -43,39 +42,45 @@ import com.google.common.util.concurrent.MoreExecutors;
 @SuppressWarnings("deprecation")
 public class CrossBrokerMountPointTest {
 
-    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
-    private static final String NODE_ID = "node:1";
+    private static final QName TLL_NAME_QNAME = QName.create(TopLevelList.QNAME, "name");
+    private static final String TLL_NAME = "foo:1";
+
+    private static final TopLevelListKey TLL_KEY = new TopLevelListKey(TLL_NAME);
 
-    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+    private static final Map<QName, Object> TLL_KEY_BI = Collections.<QName, Object> singletonMap(TLL_NAME_QNAME,
+            TLL_NAME);
 
-    private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
-            NODE_ID);
+    private static final InstanceIdentifier<TopLevelList> TLL_INSTANCE_ID_BA = InstanceIdentifier.builder(Top.class) //
+            .child(TopLevelList.class, TLL_KEY).build();
 
-    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
-            .child(Node.class, NODE_KEY).toInstance();
-    private static GroupKey GROUP_KEY = new GroupKey(new GroupId(0L));
+    private static final List1Key LIST1_KEY = new List1Key("foo");
+    private static final List11Key LIST11_KEY = new List11Key(1);
 
-    private static final InstanceIdentifier<GroupStatistics> GROUP_STATISTICS_ID_BA = NODE_INSTANCE_ID_BA
-            .builder().augmentation(FlowCapableNode.class) //
-            .child(Group.class, GROUP_KEY) //
-            .augmentation(NodeGroupStatistics.class) //
-            .child(GroupStatistics.class) //
-            .toInstance();
+    private static final InstanceIdentifier<Cont> AUG_CONT_ID_BA = TLL_INSTANCE_ID_BA
+            .builder().augmentation(TllComplexAugment.class) //
+            .child(List1.class, LIST1_KEY) //
+            .child(List11.class, LIST11_KEY) //
+            .augmentation(List11SimpleAugment.class) //
+            .child(Cont.class) //
+            .build();
 
-    private static final QName AUGMENTED_GROUP_STATISTICS = QName.create(NodeGroupStatistics.QNAME,
-            GroupStatistics.QNAME.getLocalName());
+    private static final QName AUG_CONT = QName.create(List11.QNAME,
+            Cont.QNAME.getLocalName());
 
-    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier NODE_INSTANCE_ID_BI = //
+    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier TLL_INSTANCE_ID_BI = //
     org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder() //
-            .node(Nodes.QNAME) //
-            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
-            .toInstance();
+            .node(Top.QNAME) //
+            .nodeWithKey(TopLevelList.QNAME, TLL_KEY_BI) //
+            .build();
 
     private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier GROUP_STATISTICS_ID_BI = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
             //
-            .builder(NODE_INSTANCE_ID_BI)
-            .nodeWithKey(QName.create(FlowCapableNode.QNAME, "group"), QName.create(FlowCapableNode.QNAME, "group-id"),
-                    0L).node(AUGMENTED_GROUP_STATISTICS).toInstance();
+            .builder(TLL_INSTANCE_ID_BI)
+            .nodeWithKey(QName.create(TllComplexAugment.QNAME, "list1"), QName.create(TllComplexAugment.QNAME, "attr-str"),
+                    LIST1_KEY.getAttrStr())
+            .nodeWithKey(QName.create(TllComplexAugment.QNAME, "list1-1"), QName.create(TllComplexAugment.QNAME, "attr-int"),
+                    LIST11_KEY.getAttrInt())
+            .node(AUG_CONT).build();
 
     private BindingTestContext testContext;
     private MountProviderService bindingMountPointService;
@@ -102,14 +107,14 @@ public class CrossBrokerMountPointTest {
     @Test
     public void testMountPoint() {
 
-        testContext.getBindingDataBroker().readOperationalData(NODE_INSTANCE_ID_BA);
+        testContext.getBindingDataBroker().readOperationalData(TLL_INSTANCE_ID_BA);
 
-        MountProvisionInstance domMountPoint = domMountPointService.createMountPoint(NODE_INSTANCE_ID_BI);
+        MountProvisionInstance domMountPoint = domMountPointService.createMountPoint(TLL_INSTANCE_ID_BI);
         assertNotNull(domMountPoint);
-        MountProviderInstance bindingMountPoint = bindingMountPointService.getMountPoint(NODE_INSTANCE_ID_BA);
+        MountProviderInstance bindingMountPoint = bindingMountPointService.getMountPoint(TLL_INSTANCE_ID_BA);
         assertNotNull(bindingMountPoint);
 
-        final BigInteger packetCount = BigInteger.valueOf(500L);
+        final Integer attrIntalue = 500;
 
 
         DataReader<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, CompositeNode> simpleReader = new DataReader<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, CompositeNode>() {
@@ -125,9 +130,9 @@ public class CrossBrokerMountPointTest {
                 if (arg0.equals(GROUP_STATISTICS_ID_BI)) {
                     ImmutableCompositeNode data = ImmutableCompositeNode
                             .builder()
-                            .setQName(AUGMENTED_GROUP_STATISTICS)
-                            .addLeaf(QName.create(AUGMENTED_GROUP_STATISTICS, "packet-count"), packetCount) //
-                            .toInstance();
+                            .setQName(AUG_CONT)
+                            .addLeaf(QName.create(AUG_CONT, "attr-int"), attrIntalue) //
+                            .build();
 
                     return data;
                 }
@@ -135,10 +140,10 @@ public class CrossBrokerMountPointTest {
             }
 
         };
-        domMountPoint.registerOperationalReader(NODE_INSTANCE_ID_BI, simpleReader);
+        domMountPoint.registerOperationalReader(TLL_INSTANCE_ID_BI, simpleReader);
 
-        GroupStatistics data = (GroupStatistics) bindingMountPoint.readOperationalData(GROUP_STATISTICS_ID_BA);
+        Cont data = (Cont) bindingMountPoint.readOperationalData(AUG_CONT_ID_BA);
         assertNotNull(data);
-        assertEquals(packetCount,data.getPacketCount().getValue());
+        assertEquals(attrIntalue ,data.getAttrInt());
     }
 }
index ba75d578fbb770e94fc49ee18bed36739adb837c..83c2f88376239a29bd0bf09060dc981fff2a1f65 100644 (file)
@@ -12,11 +12,10 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
-import java.math.BigInteger;
-import java.util.Collections;
-import java.util.Set;
-import java.util.concurrent.Future;
-
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -25,19 +24,15 @@ import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactor
 import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
-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.AddFlowOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.KnockKnockInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.KnockKnockInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.KnockKnockOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.KnockKnockOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.OpendaylightOfMigrationTestModelService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.rpc.routing.rev140701.TestContext;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -45,38 +40,31 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.Future;
 
 public class CrossBrokerRpcTest {
 
-    protected RpcProviderRegistry baRpcRegistry;
-    protected RpcProvisionRegistry biRpcRegistry;
+    protected RpcProviderRegistry providerRegistry;
+    protected RpcProvisionRegistry provisionRegistry;
     private BindingTestContext testContext;
     private RpcImplementation biRpcInvoker;
-    private MessageCapturingFlowService flowService;
+    private MessageCapturingFlowService knockService;
 
-    public static final NodeId NODE_A = new NodeId("a");
-    public static final NodeId NODE_B = new NodeId("b");
-    public static final NodeId NODE_C = new NodeId("c");
-    public static final NodeId NODE_D = new NodeId("d");
+    public static final TopLevelListKey NODE_A = new TopLevelListKey("a");
+    public static final TopLevelListKey NODE_B = new TopLevelListKey("b");
+    public static final TopLevelListKey NODE_C = new TopLevelListKey("c");
 
-    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
-    private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow");
+    private static final QName NODE_ID_QNAME = QName.create(TopLevelList.QNAME, "name");
+    private static final QName KNOCK_KNOCK_QNAME = QName.create(KnockKnockOutput.QNAME, "knock-knock");
 
-    public static final InstanceIdentifier<Node> BA_NODE_A_ID = createBANodeIdentifier(NODE_A);
-    public static final InstanceIdentifier<Node> BA_NODE_B_ID = createBANodeIdentifier(NODE_B);
-    public static final InstanceIdentifier<Node> BA_NODE_C_ID = createBANodeIdentifier(NODE_C);
-    public static final InstanceIdentifier<Node> BA_NODE_D_ID = createBANodeIdentifier(NODE_D);
+    public static final InstanceIdentifier<Top> NODES_PATH = InstanceIdentifier.builder(Top.class).build();
+    public static final InstanceIdentifier<TopLevelList> BA_NODE_A_ID = NODES_PATH.child(TopLevelList.class, NODE_A);
+    public static final InstanceIdentifier<TopLevelList> BA_NODE_B_ID = NODES_PATH.child(TopLevelList.class, NODE_B);
+    public static final InstanceIdentifier<TopLevelList> BA_NODE_C_ID = NODES_PATH.child(TopLevelList.class, NODE_C);
 
-    public static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier BI_NODE_A_ID = createBINodeIdentifier(NODE_A);
-    public static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier BI_NODE_B_ID = createBINodeIdentifier(NODE_B);
     public static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C);
-    public static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D);
-
 
 
     @Before
@@ -87,48 +75,49 @@ public class CrossBrokerRpcTest {
         testContext = testFactory.getTestContext();
 
         testContext.start();
-        baRpcRegistry = testContext.getBindingRpcRegistry();
-        biRpcRegistry = testContext.getDomRpcRegistry();
+        providerRegistry = testContext.getBindingRpcRegistry();
+        provisionRegistry = testContext.getDomRpcRegistry();
         biRpcInvoker = testContext.getDomRpcInvoker();
-        assertNotNull(baRpcRegistry);
-        assertNotNull(biRpcRegistry);
+        assertNotNull(providerRegistry);
+        assertNotNull(provisionRegistry);
 
-        flowService = MessageCapturingFlowService.create(baRpcRegistry);
+        knockService = MessageCapturingFlowService.create(providerRegistry);
 
     }
 
     @Test
     public void bindingRoutedRpcProvider_DomInvokerTest() throws Exception {
 
-        flowService//
-                .registerPath(NodeContext.class, BA_NODE_A_ID) //
-                .registerPath(NodeContext.class, BA_NODE_B_ID) //
-                .setAddFlowResult(addFlowResult(true, 10));
+        knockService//
+                .registerPath(TestContext.class, BA_NODE_A_ID) //
+                .registerPath(TestContext.class, BA_NODE_B_ID) //
+                .setKnockKnockResult(knockResult(true, "open"));
 
-        SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class);
-        assertNotSame(flowService, baFlowInvoker);
+        OpendaylightOfMigrationTestModelService baKnockInvoker =
+                providerRegistry.getRpcService(OpendaylightOfMigrationTestModelService.class);
+        assertNotSame(knockService, baKnockInvoker);
 
-        AddFlowInput addFlowA = addFlow(BA_NODE_A_ID) //
-                .setPriority(100).setBarrier(true).build();
+        KnockKnockInput knockKnockA = knockKnock(BA_NODE_A_ID) //
+                .setQuestion("who's there?").build();
 
-        CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA);
-        assertNotNull(addFlowDom);
-        RpcResult<CompositeNode> domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom).get();
+        CompositeNode knockKnockDom = toDomRpc(KNOCK_KNOCK_QNAME, knockKnockA);
+        assertNotNull(knockKnockDom);
+        RpcResult<CompositeNode> domResult = biRpcInvoker.invokeRpc(KNOCK_KNOCK_QNAME, knockKnockDom).get();
         assertNotNull(domResult);
         assertTrue("DOM result is successful.", domResult.isSuccessful());
-        assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID));
-        assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next());
+        assertTrue("Bidning Add Flow RPC was captured.", knockService.getReceivedKnocks().containsKey(BA_NODE_A_ID));
+        assertEquals(knockKnockA, knockService.getReceivedKnocks().get(BA_NODE_A_ID).iterator().next());
     }
 
     @Test
     public void bindingRpcInvoker_DomRoutedProviderTest() throws Exception {
-        AddFlowOutputBuilder builder = new AddFlowOutputBuilder();
-        builder.setTransactionId(new TransactionId(BigInteger.valueOf(10)));
-        final AddFlowOutput output = builder.build();
-        org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration registration = biRpcRegistry.addRoutedRpcImplementation(ADD_FLOW_QNAME, new RpcImplementation() {
+        KnockKnockOutputBuilder builder = new KnockKnockOutputBuilder();
+        builder.setAnswer("open");
+        final KnockKnockOutput output = builder.build();
+        org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration registration = provisionRegistry.addRoutedRpcImplementation(KNOCK_KNOCK_QNAME, new RpcImplementation() {
             @Override
             public Set<QName> getSupportedRpcs() {
-                return ImmutableSet.of(ADD_FLOW_QNAME);
+                return ImmutableSet.of(KNOCK_KNOCK_QNAME);
             }
 
             @Override
@@ -137,12 +126,14 @@ public class CrossBrokerRpcTest {
                 return Futures.immediateFuture(RpcResultBuilder.<CompositeNode>success(result).build());
             }
         });
-        registration.registerPath(NodeContext.QNAME, BI_NODE_C_ID);
+        registration.registerPath(TestContext.QNAME, BI_NODE_C_ID);
+
 
-        SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class);
-        Future<RpcResult<AddFlowOutput>> baResult = baFlowInvoker.addFlow(addFlow(BA_NODE_C_ID).setPriority(500).build());
+        OpendaylightOfMigrationTestModelService baKnockInvoker =
+                providerRegistry.getRpcService(OpendaylightOfMigrationTestModelService.class);
+        Future<RpcResult<KnockKnockOutput>> baResult = baKnockInvoker.knockKnock((knockKnock(BA_NODE_C_ID).setQuestion("Who's there?").build()));
         assertNotNull(baResult);
-        assertEquals(output,baResult.get().getResult());
+        assertEquals(output, baResult.get().getResult());
     }
 
     private CompositeNode toDomRpcInput(DataObject addFlowA) {
@@ -154,30 +145,26 @@ public class CrossBrokerRpcTest {
         testContext.close();
     }
 
-    private static InstanceIdentifier<Node> createBANodeIdentifier(NodeId node) {
-        return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(node)).toInstance();
-    }
-
-    private static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier createBINodeIdentifier(NodeId node) {
-        return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder().node(Nodes.QNAME)
-                .nodeWithKey(Node.QNAME, NODE_ID_QNAME, node.getValue()).toInstance();
+    private static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier createBINodeIdentifier(TopLevelListKey listKey) {
+        return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder().node(Top.QNAME)
+                .nodeWithKey(TopLevelList.QNAME, NODE_ID_QNAME, listKey.getName()).toInstance();
     }
 
-    private Future<RpcResult<AddFlowOutput>> addFlowResult(boolean success, long xid) {
-        AddFlowOutput output = new AddFlowOutputBuilder() //
-                .setTransactionId(new TransactionId(BigInteger.valueOf(xid))).build();
-        RpcResult<AddFlowOutput> result = RpcResultBuilder.<AddFlowOutput>status(success).withResult(output).build();
+    private Future<RpcResult<KnockKnockOutput>> knockResult(boolean success, String answer) {
+        KnockKnockOutput output = new KnockKnockOutputBuilder() //
+                .setAnswer(answer).build();
+        RpcResult<KnockKnockOutput> result = RpcResultBuilder.<KnockKnockOutput>status(success).withResult(output).build();
         return Futures.immediateFuture(result);
     }
 
-    private static AddFlowInputBuilder addFlow(InstanceIdentifier<Node> nodeId) {
-        AddFlowInputBuilder builder = new AddFlowInputBuilder();
-        builder.setNode(new NodeRef(nodeId));
+    private static KnockKnockInputBuilder knockKnock(InstanceIdentifier<TopLevelList> listId) {
+        KnockKnockInputBuilder builder = new KnockKnockInputBuilder();
+        builder.setKnockerId(listId);
         return builder;
     }
 
-    private CompositeNode toDomRpc(QName rpcName, AddFlowInput addFlowA) {
+    private CompositeNode toDomRpc(QName rpcName, KnockKnockInput knockInput) {
         return new CompositeNodeTOImpl(rpcName, null,
-                Collections.<org.opendaylight.yangtools.yang.data.api.Node<?>> singletonList(toDomRpcInput(addFlowA)));
+                Collections.<org.opendaylight.yangtools.yang.data.api.Node<?>>singletonList(toDomRpcInput(knockInput)));
     }
 }
index 7d616ca62cdaa02648927809a37468ca2a9702a3..7595ec01059ce9772ad84bada2a5b55e1db5d693 100644 (file)
@@ -28,12 +28,11 @@ import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
-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.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.bi.ba.rpcservice.rev140701.OpendaylightTestRpcServiceService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.bi.ba.rpcservice.rev140701.RockTheHouseInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -64,11 +63,11 @@ public class DOMRpcServiceTestBugfix560 {
     private final static QName RPC_NAME = QName.create(RPC_SERVICE_NAMESPACE,
             REVISION_DATE, "rock-the-house");
 
-    private static final NodeId MOUNT_NODE = new NodeId("id");
-    private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+    private static final String TLL_NAME = "id";
+    private static final QName TLL_NAME_QNAME = QName.create(TopLevelList.QNAME, "name");
 
-    private static final InstanceIdentifier<Node> BA_MOUNT_ID = createBANodeIdentifier(MOUNT_NODE);
-    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier BI_MOUNT_ID = createBINodeIdentifier(MOUNT_NODE);
+    private static final InstanceIdentifier<TopLevelList> BA_MOUNT_ID = createBATllIdentifier(TLL_NAME);
+    private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier BI_MOUNT_ID = createBITllIdentifier(TLL_NAME);
 
     private BindingTestContext testContext;
     private MountProvisionService domMountPointService;
@@ -104,18 +103,18 @@ public class DOMRpcServiceTestBugfix560 {
         schemaContext = mountSchemaContext;
     }
 
-    private static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier createBINodeIdentifier(
-            final NodeId mountNode) {
+    private static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier createBITllIdentifier(
+            final String mount) {
         return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
-                .builder().node(Nodes.QNAME)
-                .nodeWithKey(Node.QNAME, NODE_ID_QNAME, mountNode.getValue())
+                .builder().node(Top.QNAME)
+                .nodeWithKey(TopLevelList.QNAME, TLL_NAME_QNAME, mount)
                 .toInstance();
     }
 
-    private static InstanceIdentifier<Node> createBANodeIdentifier(
-            final NodeId mountNode) {
-        return InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, new NodeKey(mountNode)).toInstance();
+    private static InstanceIdentifier<TopLevelList> createBATllIdentifier(
+            final String mount) {
+        return InstanceIdentifier.builder(Top.class)
+                .child(TopLevelList.class, new TopLevelListKey(mount)).toInstance();
     }
 
     @SuppressWarnings("deprecation")
index 47e79650fe1d865b0db61ccb733de584fa45de4c..0f9389703ff5b587a1068a2428ca5d1732907f2c 100644 (file)
@@ -11,15 +11,11 @@ import static org.junit.Assert.assertNotNull;
 
 import java.util.concurrent.Future;
 
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
-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.UpdateFlowOutput;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.KnockKnockInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.KnockKnockOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.of.migration.test.model.rev150210.OpendaylightOfMigrationTestModelService;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -27,76 +23,28 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 
-public class MessageCapturingFlowService implements SalFlowService, AutoCloseable {
-
-    private Future<RpcResult<AddFlowOutput>> addFlowResult;
-    private Future<RpcResult<RemoveFlowOutput>> removeFlowResult;
-    private Future<RpcResult<UpdateFlowOutput>> updateFlowResult;
-
-    private final Multimap<InstanceIdentifier<?>, AddFlowInput> receivedAddFlows = HashMultimap.create();
-    private final Multimap<InstanceIdentifier<?>, RemoveFlowInput> receivedRemoveFlows = HashMultimap.create();
-    private final Multimap<InstanceIdentifier<?>, UpdateFlowInput> receivedUpdateFlows = HashMultimap.create();
-    private RoutedRpcRegistration<SalFlowService> registration;
-
-    @Override
-    public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput arg0) {
-        receivedAddFlows.put(arg0.getNode().getValue(), arg0);
-        return addFlowResult;
-    }
-
-    @Override
-    public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput arg0) {
-        receivedRemoveFlows.put(arg0.getNode().getValue(), arg0);
-        return removeFlowResult;
-    }
-
-    @Override
-    public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput arg0) {
-        receivedUpdateFlows.put(arg0.getNode().getValue(), arg0);
-        return updateFlowResult;
-    }
-
-    public Future<RpcResult<AddFlowOutput>> getAddFlowResult() {
-        return addFlowResult;
-    }
+public class MessageCapturingFlowService implements OpendaylightOfMigrationTestModelService, AutoCloseable {
 
-    public MessageCapturingFlowService setAddFlowResult(Future<RpcResult<AddFlowOutput>> addFlowResult) {
-        this.addFlowResult = addFlowResult;
-        return this;
-    }
+    private Future<RpcResult<KnockKnockOutput>> knockKnockResult;
 
-    public Future<RpcResult<RemoveFlowOutput>> getRemoveFlowResult() {
-        return removeFlowResult;
-    }
-
-    public MessageCapturingFlowService setRemoveFlowResult(Future<RpcResult<RemoveFlowOutput>> removeFlowResult) {
-        this.removeFlowResult = removeFlowResult;
-        return this;
-    }
+    private final Multimap<InstanceIdentifier<?>, KnockKnockInput> receivedKnocks = HashMultimap.create();
+    private RoutedRpcRegistration<OpendaylightOfMigrationTestModelService> registration;
 
-    public Future<RpcResult<UpdateFlowOutput>> getUpdateFlowResult() {
-        return updateFlowResult;
+    public Future<RpcResult<KnockKnockOutput>> getKnockKnockResult() {
+        return knockKnockResult;
     }
 
-    public MessageCapturingFlowService setUpdateFlowResult(Future<RpcResult<UpdateFlowOutput>> updateFlowResult) {
-        this.updateFlowResult = updateFlowResult;
+    public MessageCapturingFlowService setKnockKnockResult(Future<RpcResult<KnockKnockOutput>> kkOutput) {
+        this.knockKnockResult = kkOutput;
         return this;
     }
 
-    public Multimap<InstanceIdentifier<?>, AddFlowInput> getReceivedAddFlows() {
-        return receivedAddFlows;
-    }
-
-    public Multimap<InstanceIdentifier<?>, RemoveFlowInput> getReceivedRemoveFlows() {
-        return receivedRemoveFlows;
-    }
-
-    public Multimap<InstanceIdentifier<?>, UpdateFlowInput> getReceivedUpdateFlows() {
-        return receivedUpdateFlows;
+    public Multimap<InstanceIdentifier<?>, KnockKnockInput> getReceivedKnocks() {
+        return receivedKnocks;
     }
 
     public MessageCapturingFlowService registerTo(RpcProviderRegistry registry) {
-        registration = registry.addRoutedRpcImplementation(SalFlowService.class, this);
+        registration = registry.addRoutedRpcImplementation(OpendaylightOfMigrationTestModelService.class, this);
         assertNotNull(registration);
         return this;
     }
@@ -125,5 +73,11 @@ public class MessageCapturingFlowService implements SalFlowService, AutoCloseabl
         return ret;
     }
 
+    @Override
+    public Future<RpcResult<KnockKnockOutput>> knockKnock(KnockKnockInput input) {
+        receivedKnocks.put(input.getKnockerId(), input);
+        return knockKnockResult;
+    }
+
 
 }
index 9da6a3b5a41a025fd1a3ffcf30d42789701a6bc1..e72f4b2675eb886226ad660204fe706513937094 100644 (file)
@@ -13,17 +13,27 @@ odl-cluster-data {
     loggers = ["akka.event.slf4j.Slf4jLogger"]
 
     actor {
-
       provider = "akka.cluster.ClusterActorRefProvider"
       serializers {
-                java = "akka.serialization.JavaSerializer"
-                proto = "akka.remote.serialization.ProtobufSerializer"
-              }
+        java = "akka.serialization.JavaSerializer"
+        proto = "akka.remote.serialization.ProtobufSerializer"
+      }
+
+      serialization-bindings {
+        "com.google.protobuf.Message" = proto
+      }
 
-              serialization-bindings {
-                  "com.google.protobuf.Message" = proto
+      default-dispatcher {
+        # Setting throughput to 1 makes the dispatcher fair. It processes 1 message from
+        # the mailbox before moving on to the next mailbox
+        throughput = 1
+      }
 
-              }
+      default-mailbox {
+        # When not using a BalancingDispatcher it is recommended that we use the SingleConsumerOnlyUnboundedMailbox
+        # as it is the most efficient for multiple producer/single consumer use cases
+        mailbox-type="akka.dispatch.SingleConsumerOnlyUnboundedMailbox"
+      }
     }
     remote {
       log-remote-lifecycle-events = off
index e8b239d2c490049b2ea88768799ddda3ab1bff38..b4dcb1167c70d8743d73ba106e2aaf4842017489 100644 (file)
@@ -14,10 +14,8 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Map;
 
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
@@ -106,24 +104,6 @@ public class DataNormalizer {
                         normalizedPath), e);
             }
         }
-
-        // Write Augmentation data resolution
-        if (legacyData.getValue().size() == 1) {
-            final DataNormalizationOperation<?> potentialOp;
-
-            try {
-                final QName childType = legacyData.getValue().get(0).getNodeType();
-                potentialOp = currentOp.getChild(childType);
-            } catch (DataNormalizationException e) {
-                throw new IllegalArgumentException(String.format("Failed to get child operation for %s", legacyData), e);
-            }
-
-            if (potentialOp.getIdentifier() instanceof AugmentationIdentifier) {
-                currentOp = potentialOp;
-                normalizedPath = normalizedPath.node(potentialOp.getIdentifier());
-            }
-        }
-
         Preconditions.checkArgument(currentOp != null,
                 "Instance Identifier %s does not reference correct schema Node.", normalizedPath);
         return new AbstractMap.SimpleEntry<YangInstanceIdentifier, NormalizedNode<?, ?>>(normalizedPath,
index e841b866ba64976159895f9de8f0333759ce4ee6..ce9379a4ad9d03035dd3bbe734ac3863845be4aa 100644 (file)
@@ -668,10 +668,6 @@ public class DataNormalizerTest {
                 YangInstanceIdentifier.create(Lists.newArrayList(new NodeIdentifier(TEST_QNAME), new NodeIdentifier(
                         OUTER_CONTAINER_QNAME))), outerContBuilder.toInstance()));
 
-        verifyNormalizedInstanceIdentifier(normalizedNodeEntry.getKey(), TEST_QNAME, OUTER_CONTAINER_QNAME,
-                Sets.newHashSet(AUGMENTED_LEAF_QNAME));
-
-        verifyNormalizedNode(normalizedNodeEntry.getValue(), expAugmentation);
     }
 
     @Test
index 13334c927236cdbeba31bf82ee10fb4f7d0cc952..886c4730678208fdbf129be10463eddf252f5c0f 100644 (file)
@@ -8,13 +8,13 @@
 package org.opendaylight.controller.cluster.datastore;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
 import com.google.common.util.concurrent.AbstractFuture;
 import com.google.common.util.concurrent.AbstractListeningExecutorService;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
@@ -70,17 +70,16 @@ public class ConcurrentDOMDataBroker extends AbstractDOMDataBroker {
 
     @Override
     public CheckedFuture<Void, TransactionCommitFailedException> submit(DOMDataWriteTransaction transaction,
-            Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
+            Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
 
         Preconditions.checkArgument(transaction != null, "Transaction must not be null.");
         Preconditions.checkArgument(cohorts != null, "Cohorts must not be null.");
         LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier());
 
-        final int cohortSize = Iterables.size(cohorts);
         final AsyncNotifyingSettableFuture clientSubmitFuture =
                 new AsyncNotifyingSettableFuture(clientFutureCallbackExecutor);
 
-        doCanCommit(clientSubmitFuture, transaction, cohorts, cohortSize);
+        doCanCommit(clientSubmitFuture, transaction, cohorts);
 
         return MappingCheckedFuture.create(clientSubmitFuture,
                 TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER);
@@ -88,31 +87,31 @@ public class ConcurrentDOMDataBroker extends AbstractDOMDataBroker {
 
     private void doCanCommit(final AsyncNotifyingSettableFuture clientSubmitFuture,
             final DOMDataWriteTransaction transaction,
-            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final int cohortSize) {
+            final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
 
         final long startTime = System.nanoTime();
 
         // Not using Futures.allAsList here to avoid its internal overhead.
-        final AtomicInteger remaining = new AtomicInteger(cohortSize);
+        final AtomicInteger remaining = new AtomicInteger(cohorts.size());
         FutureCallback<Boolean> futureCallback = new FutureCallback<Boolean>() {
             @Override
             public void onSuccess(Boolean result) {
                 if (result == null || !result) {
-                    handleException(clientSubmitFuture, transaction, cohorts, cohortSize,
+                    handleException(clientSubmitFuture, transaction, cohorts,
                             CAN_COMMIT, TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER,
                             new TransactionCommitFailedException(
                                             "Can Commit failed, no detailed cause available."));
                 } else {
                     if(remaining.decrementAndGet() == 0) {
                         // All cohorts completed successfully - we can move on to the preCommit phase
-                        doPreCommit(startTime, clientSubmitFuture, transaction, cohorts, cohortSize);
+                        doPreCommit(startTime, clientSubmitFuture, transaction, cohorts);
                     }
                 }
             }
 
             @Override
             public void onFailure(Throwable t) {
-                handleException(clientSubmitFuture, transaction, cohorts, cohortSize, CAN_COMMIT,
+                handleException(clientSubmitFuture, transaction, cohorts, CAN_COMMIT,
                         TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER, t);
             }
         };
@@ -125,22 +124,22 @@ public class ConcurrentDOMDataBroker extends AbstractDOMDataBroker {
 
     private void doPreCommit(final long startTime, final AsyncNotifyingSettableFuture clientSubmitFuture,
             final DOMDataWriteTransaction transaction,
-            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final int cohortSize) {
+            final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
 
         // Not using Futures.allAsList here to avoid its internal overhead.
-        final AtomicInteger remaining = new AtomicInteger(cohortSize);
+        final AtomicInteger remaining = new AtomicInteger(cohorts.size());
         FutureCallback<Void> futureCallback = new FutureCallback<Void>() {
             @Override
             public void onSuccess(Void notUsed) {
                 if(remaining.decrementAndGet() == 0) {
                     // All cohorts completed successfully - we can move on to the commit phase
-                    doCommit(startTime, clientSubmitFuture, transaction, cohorts, cohortSize);
+                    doCommit(startTime, clientSubmitFuture, transaction, cohorts);
                 }
             }
 
             @Override
             public void onFailure(Throwable t) {
-                handleException(clientSubmitFuture, transaction, cohorts, cohortSize, PRE_COMMIT,
+                handleException(clientSubmitFuture, transaction, cohorts, PRE_COMMIT,
                         TransactionCommitFailedExceptionMapper.PRE_COMMIT_MAPPER, t);
             }
         };
@@ -153,10 +152,10 @@ public class ConcurrentDOMDataBroker extends AbstractDOMDataBroker {
 
     private void doCommit(final long startTime, final AsyncNotifyingSettableFuture clientSubmitFuture,
             final DOMDataWriteTransaction transaction,
-            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final int cohortSize) {
+            final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
 
         // Not using Futures.allAsList here to avoid its internal overhead.
-        final AtomicInteger remaining = new AtomicInteger(cohortSize);
+        final AtomicInteger remaining = new AtomicInteger(cohorts.size());
         FutureCallback<Void> futureCallback = new FutureCallback<Void>() {
             @Override
             public void onSuccess(Void notUsed) {
@@ -170,7 +169,7 @@ public class ConcurrentDOMDataBroker extends AbstractDOMDataBroker {
 
             @Override
             public void onFailure(Throwable t) {
-                handleException(clientSubmitFuture, transaction, cohorts, cohortSize, COMMIT,
+                handleException(clientSubmitFuture, transaction, cohorts, COMMIT,
                         TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER, t);
             }
         };
@@ -183,7 +182,7 @@ public class ConcurrentDOMDataBroker extends AbstractDOMDataBroker {
 
     private void handleException(final AsyncNotifyingSettableFuture clientSubmitFuture,
             final DOMDataWriteTransaction transaction,
-            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, int cohortSize,
+            final Collection<DOMStoreThreePhaseCommitCohort> cohorts,
             final String phase, final TransactionCommitFailedExceptionMapper exMapper,
             final Throwable t) {
 
@@ -205,7 +204,7 @@ public class ConcurrentDOMDataBroker extends AbstractDOMDataBroker {
         // Transaction failed - tell all cohorts to abort.
 
         @SuppressWarnings("unchecked")
-        ListenableFuture<Void>[] canCommitFutures = new ListenableFuture[cohortSize];
+        ListenableFuture<Void>[] canCommitFutures = new ListenableFuture[cohorts.size()];
         int i = 0;
         for(DOMStoreThreePhaseCommitCohort cohort: cohorts) {
             canCommitFutures[i++] = cohort.abort();
index 06f3afc57cb19d13dfd75448ce59dcf1a1e6bf39..681132e660d9608f3dea75e58eb4a9f3809f8dd6 100644 (file)
@@ -12,6 +12,7 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
 import akka.actor.PoisonPill;
 import akka.dispatch.OnComplete;
+import com.google.common.annotations.VisibleForTesting;
 import org.opendaylight.controller.cluster.datastore.exceptions.LocalShardNotFoundException;
 import org.opendaylight.controller.cluster.datastore.messages.CloseDataChangeListenerRegistration;
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
@@ -25,7 +26,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import com.google.common.annotations.VisibleForTesting;
 import scala.concurrent.Future;
 
 /**
@@ -93,7 +93,7 @@ public class DataChangeListenerRegistrationProxy implements ListenerRegistration
     public void init(final YangInstanceIdentifier path, final AsyncDataBroker.DataChangeScope scope) {
 
         dataChangeListenerActor = actorContext.getActorSystem().actorOf(
-                DataChangeListener.props(listener));
+                DataChangeListener.props(listener).withDispatcher(actorContext.getNotificationDispatcherPath()));
 
         Future<ActorRef> findFuture = actorContext.findLocalShardAsync(shardName);
         findFuture.onComplete(new OnComplete<ActorRef>() {
@@ -109,7 +109,7 @@ public class DataChangeListenerRegistrationProxy implements ListenerRegistration
                     doRegistration(shard, path, scope);
                 }
             }
-        }, actorContext.getActorSystem().dispatcher());
+        }, actorContext.getClientDispatcher());
     }
 
     private void doRegistration(ActorRef shard, final YangInstanceIdentifier path,
@@ -131,7 +131,7 @@ public class DataChangeListenerRegistrationProxy implements ListenerRegistration
                             reply.getListenerRegistrationPath()));
                 }
             }
-        }, actorContext.getActorSystem().dispatcher());
+        }, actorContext.getClientDispatcher());
     }
 
     @Override
index 107c959112fbc34398ae48b144752a8b28c99e41..afbdbe1fe9859d15bbcf5d319112c87c5d054698 100644 (file)
@@ -14,6 +14,7 @@ import com.google.common.base.Preconditions;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardManagerIdentifier;
 import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory;
 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
+import org.opendaylight.controller.cluster.datastore.utils.Dispatchers;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
@@ -52,9 +53,12 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au
 
         LOG.info("Creating ShardManager : {}", shardManagerId);
 
+        String shardDispatcher =
+                new Dispatchers(actorSystem.dispatchers()).getDispatcherPath(Dispatchers.DispatcherType.Shard);
+
         actorContext = new ActorContext(actorSystem, actorSystem.actorOf(
                 ShardManager.props(cluster, configuration, datastoreContext)
-                    .withMailbox(ActorContext.MAILBOX), shardManagerId ),
+                        .withDispatcher(shardDispatcher).withMailbox(ActorContext.MAILBOX), shardManagerId ),
                 cluster, configuration, datastoreContext);
     }
 
index 21d74a6e1a37d49ad9ea6e53b731014e4020f01b..0672023fcbfe0e207036006d85ca9d1509a94a38 100644 (file)
@@ -60,10 +60,13 @@ import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContex
 import org.opendaylight.controller.cluster.datastore.modification.Modification;
 import org.opendaylight.controller.cluster.datastore.modification.ModificationPayload;
 import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.utils.Dispatchers;
+import org.opendaylight.controller.cluster.datastore.utils.MessageTracker;
 import org.opendaylight.controller.cluster.datastore.utils.SerializationUtils;
 import org.opendaylight.controller.cluster.notifications.RoleChangeNotifier;
 import org.opendaylight.controller.cluster.raft.RaftActor;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
+import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
@@ -71,6 +74,7 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListene
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionFactory;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
@@ -125,6 +129,8 @@ public class Shard extends RaftActor {
 
     private final Optional<ActorRef> roleChangeNotifier;
 
+    private final MessageTracker appendEntriesReplyTracker;
+
     /**
      * Coordinates persistence recovery on startup.
      */
@@ -133,6 +139,8 @@ public class Shard extends RaftActor {
 
     private final Map<String, DOMStoreTransactionChain> transactionChains = new HashMap<>();
 
+    private final String txnDispatcherPath;
+
     protected Shard(final ShardIdentifier name, final Map<ShardIdentifier, String> peerAddresses,
             final DatastoreContext datastoreContext, final SchemaContext schemaContext) {
         super(name.toString(), mapPeerAddresses(peerAddresses),
@@ -141,7 +149,11 @@ public class Shard extends RaftActor {
         this.name = name;
         this.datastoreContext = datastoreContext;
         this.schemaContext = schemaContext;
-        this.dataPersistenceProvider = (datastoreContext.isPersistent()) ? new PersistentDataProvider() : new NonPersistentRaftDataProvider();
+        this.dataPersistenceProvider = (datastoreContext.isPersistent())
+                ? new PersistentDataProvider() : new NonPersistentRaftDataProvider();
+        this.txnDispatcherPath = new Dispatchers(context().system().dispatchers())
+                .getDispatcherPath(Dispatchers.DispatcherType.Transaction);
+
 
         LOG.info("Shard created : {}, persistent : {}", name, datastoreContext.isPersistent());
 
@@ -168,6 +180,9 @@ public class Shard extends RaftActor {
 
         // create a notifier actor for each cluster member
         roleChangeNotifier = createRoleChangeNotifier(name.toString());
+
+        appendEntriesReplyTracker = new MessageTracker(AppendEntriesReply.class,
+                getRaftActorContext().getConfigParams().getIsolatedCheckIntervalInMillis());
     }
 
     private static Map<String, String> mapPeerAddresses(
@@ -224,35 +239,50 @@ public class Shard extends RaftActor {
             onRecoveryComplete();
         } else {
             super.onReceiveRecover(message);
+            if(LOG.isTraceEnabled()) {
+                appendEntriesReplyTracker.begin();
+            }
         }
     }
 
     @Override
     public void onReceiveCommand(final Object message) throws Exception {
-        if (message.getClass().equals(CreateTransaction.SERIALIZABLE_CLASS)) {
-            handleCreateTransaction(message);
-        } else if(message instanceof ForwardedReadyTransaction) {
-            handleForwardedReadyTransaction((ForwardedReadyTransaction)message);
-        } else if(message.getClass().equals(CanCommitTransaction.SERIALIZABLE_CLASS)) {
-            handleCanCommitTransaction(CanCommitTransaction.fromSerializable(message));
-        } else if(message.getClass().equals(CommitTransaction.SERIALIZABLE_CLASS)) {
-            handleCommitTransaction(CommitTransaction.fromSerializable(message));
-        } else if(message.getClass().equals(AbortTransaction.SERIALIZABLE_CLASS)) {
-            handleAbortTransaction(AbortTransaction.fromSerializable(message));
-        } else if (message.getClass().equals(CloseTransactionChain.SERIALIZABLE_CLASS)){
-            closeTransactionChain(CloseTransactionChain.fromSerializable(message));
-        } else if (message instanceof RegisterChangeListener) {
-            registerChangeListener((RegisterChangeListener) message);
-        } else if (message instanceof UpdateSchemaContext) {
-            updateSchemaContext((UpdateSchemaContext) message);
-        } else if (message instanceof PeerAddressResolved) {
-            PeerAddressResolved resolved = (PeerAddressResolved) message;
-            setPeerAddress(resolved.getPeerId().toString(),
-                resolved.getPeerAddress());
-        } else if(message.equals(TX_COMMIT_TIMEOUT_CHECK_MESSAGE)) {
-            handleTransactionCommitTimeoutCheck();
-        } else {
-            super.onReceiveCommand(message);
+
+        MessageTracker.Context context = appendEntriesReplyTracker.received(message);
+
+        if(context.error().isPresent()){
+            LOG.trace("{} : AppendEntriesReply failed to arrive at the expected interval {}", persistenceId(),
+                    context.error());
+        }
+
+        try {
+            if (message.getClass().equals(CreateTransaction.SERIALIZABLE_CLASS)) {
+                handleCreateTransaction(message);
+            } else if (message instanceof ForwardedReadyTransaction) {
+                handleForwardedReadyTransaction((ForwardedReadyTransaction) message);
+            } else if (message.getClass().equals(CanCommitTransaction.SERIALIZABLE_CLASS)) {
+                handleCanCommitTransaction(CanCommitTransaction.fromSerializable(message));
+            } else if (message.getClass().equals(CommitTransaction.SERIALIZABLE_CLASS)) {
+                handleCommitTransaction(CommitTransaction.fromSerializable(message));
+            } else if (message.getClass().equals(AbortTransaction.SERIALIZABLE_CLASS)) {
+                handleAbortTransaction(AbortTransaction.fromSerializable(message));
+            } else if (message.getClass().equals(CloseTransactionChain.SERIALIZABLE_CLASS)) {
+                closeTransactionChain(CloseTransactionChain.fromSerializable(message));
+            } else if (message instanceof RegisterChangeListener) {
+                registerChangeListener((RegisterChangeListener) message);
+            } else if (message instanceof UpdateSchemaContext) {
+                updateSchemaContext((UpdateSchemaContext) message);
+            } else if (message instanceof PeerAddressResolved) {
+                PeerAddressResolved resolved = (PeerAddressResolved) message;
+                setPeerAddress(resolved.getPeerId().toString(),
+                        resolved.getPeerAddress());
+            } else if (message.equals(TX_COMMIT_TIMEOUT_CHECK_MESSAGE)) {
+                handleTransactionCommitTimeoutCheck();
+            } else {
+                super.onReceiveCommand(message);
+            }
+        } finally {
+            context.done();
         }
     }
 
@@ -493,32 +523,19 @@ public class Shard extends RaftActor {
 
             shardMBean.incrementReadOnlyTransactionCount();
 
-            return getContext().actorOf(
-                ShardTransaction.props(factory.newReadOnlyTransaction(), getSelf(),
-                        schemaContext,datastoreContext, shardMBean,
-                        transactionId.getRemoteTransactionId(), clientVersion),
-                        transactionId.toString());
+            return createShardTransaction(factory.newReadOnlyTransaction(), transactionId, clientVersion);
 
         } else if (transactionType == TransactionProxy.TransactionType.READ_WRITE.ordinal()) {
 
             shardMBean.incrementReadWriteTransactionCount();
 
-            return getContext().actorOf(
-                ShardTransaction.props(factory.newReadWriteTransaction(), getSelf(),
-                        schemaContext, datastoreContext, shardMBean,
-                        transactionId.getRemoteTransactionId(), clientVersion),
-                        transactionId.toString());
-
+            return createShardTransaction(factory.newReadWriteTransaction(), transactionId, clientVersion);
 
         } else if (transactionType == TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) {
 
             shardMBean.incrementWriteOnlyTransactionCount();
 
-            return getContext().actorOf(
-                ShardTransaction.props(factory.newWriteOnlyTransaction(), getSelf(),
-                        schemaContext, datastoreContext, shardMBean,
-                        transactionId.getRemoteTransactionId(), clientVersion),
-                        transactionId.toString());
+            return createShardTransaction(factory.newWriteOnlyTransaction(), transactionId, clientVersion);
         } else {
             throw new IllegalArgumentException(
                 "Shard="+name + ":CreateTransaction message has unidentified transaction type="
@@ -526,6 +543,17 @@ public class Shard extends RaftActor {
         }
     }
 
+    private ActorRef createShardTransaction(DOMStoreTransaction transaction, ShardTransactionIdentifier transactionId,
+                                            short clientVersion){
+        return getContext().actorOf(
+                ShardTransaction.props(transaction, getSelf(),
+                        schemaContext, datastoreContext, shardMBean,
+                        transactionId.getRemoteTransactionId(), clientVersion)
+                        .withDispatcher(txnDispatcherPath),
+                transactionId.toString());
+
+    }
+
     private void createTransaction(CreateTransaction createTransaction) {
         try {
             ActorRef transactionActor = createTransaction(createTransaction.getTransactionType(),
index d52965e055262434c3ff34227fdd4ebca898bc5e..426a2e0934f173560647a13569b22d1e06f632b2 100644 (file)
@@ -50,6 +50,7 @@ import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolve
 import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound;
 import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound;
 import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
+import org.opendaylight.controller.cluster.datastore.utils.Dispatchers;
 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
@@ -87,6 +88,8 @@ public class ShardManager extends AbstractUntypedPersistentActorWithMetering {
 
     private final Configuration configuration;
 
+    private final String shardDispatcherPath;
+
     private ShardManagerInfoMBean mBean;
 
     private final DatastoreContext datastoreContext;
@@ -105,6 +108,8 @@ public class ShardManager extends AbstractUntypedPersistentActorWithMetering {
         this.datastoreContext = datastoreContext;
         this.dataPersistenceProvider = createDataPersistenceProvider(datastoreContext.isPersistent());
         this.type = datastoreContext.getDataStoreType();
+        this.shardDispatcherPath =
+                new Dispatchers(context().system().dispatchers()).getDispatcherPath(Dispatchers.DispatcherType.Shard);
 
         // Subscribe this actor to cluster member events
         cluster.subscribeToMemberEvents(getSelf());
@@ -283,8 +288,8 @@ public class ShardManager extends AbstractUntypedPersistentActorWithMetering {
                     for (ShardInformation info : localShards.values()) {
                         if (info.getActor() == null) {
                             info.setActor(getContext().actorOf(Shard.props(info.getShardId(),
-                                            info.getPeerAddresses(), datastoreContext, schemaContext),
-                                    info.getShardId().toString()));
+                                            info.getPeerAddresses(), datastoreContext, schemaContext)
+                                            .withDispatcher(shardDispatcherPath), info.getShardId().toString()));
                         } else {
                             info.getActor().tell(message, getSelf());
                         }
index 4f472266c1f56acbd8fc531ae7189f1ae91951b4..4445b14e2edc1b48b5c92012e8a659275357f433 100644 (file)
@@ -71,7 +71,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
     private Future<Void> buildCohortList() {
 
         Future<Iterable<ActorSelection>> combinedFutures = Futures.sequence(cohortFutures,
-                actorContext.getActorSystem().dispatcher());
+                actorContext.getClientDispatcher());
 
         return combinedFutures.transform(new AbstractFunction1<Iterable<ActorSelection>, Void>() {
             @Override
@@ -83,7 +83,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
                 }
                 return null;
             }
-        }, TransactionProxy.SAME_FAILURE_TRANSFORMER, actorContext.getActorSystem().dispatcher());
+        }, TransactionProxy.SAME_FAILURE_TRANSFORMER, actorContext.getClientDispatcher());
     }
 
     @Override
@@ -111,7 +111,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
                     finishCanCommit(returnFuture);
                 }
             }
-        }, actorContext.getActorSystem().dispatcher());
+        }, actorContext.getClientDispatcher());
 
         return returnFuture;
     }
@@ -158,7 +158,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
                 }
                 returnFuture.set(Boolean.valueOf(result));
             }
-        }, actorContext.getActorSystem().dispatcher());
+        }, actorContext.getClientDispatcher());
     }
 
     private Future<Iterable<Object>> invokeCohorts(Object message) {
@@ -170,7 +170,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
             futureList.add(actorContext.executeOperationAsync(cohort, message, actorContext.getTransactionCommitOperationTimeout()));
         }
 
-        return Futures.sequence(futureList, actorContext.getActorSystem().dispatcher());
+        return Futures.sequence(futureList, actorContext.getClientDispatcher());
     }
 
     @Override
@@ -239,7 +239,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
                                 propagateException, returnFuture, callback);
                     }
                 }
-            }, actorContext.getActorSystem().dispatcher());
+            }, actorContext.getClientDispatcher());
         }
 
         return returnFuture;
@@ -304,7 +304,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
                     callback.success();
                 }
             }
-        }, actorContext.getActorSystem().dispatcher());
+        }, actorContext.getClientDispatcher());
     }
 
     @VisibleForTesting
@@ -342,7 +342,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
             timerContext.stop();
 
             Snapshot timerSnapshot = commitTimer.getSnapshot();
-            double allowedLatencyInNanos = timerSnapshot.get98thPercentile();
+            double allowedLatencyInNanos = timerSnapshot.get95thPercentile();
 
             long commitTimeoutInSeconds = actorContext.getDatastoreContext()
                     .getShardTransactionCommitTimeoutInSeconds();
index 530a36cff657304005ebd4b43a5bb1e46449951b..03d1b3a6d736541dca754e49fa6f35ea67b7ed2b 100644 (file)
@@ -60,7 +60,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
     }
 
     private Future<Object> completeOperation(Future<Object> operationFuture){
-        operationFuture.onComplete(this.operationCompleter, actorContext.getActorSystem().dispatcher());
+        operationFuture.onComplete(this.operationCompleter, actorContext.getClientDispatcher());
         return operationFuture;
     }
 
@@ -105,7 +105,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
         futureList.add(replyFuture);
 
         Future<Iterable<Object>> combinedFutures = akka.dispatch.Futures.sequence(futureList,
-                actorContext.getActorSystem().dispatcher());
+                actorContext.getClientDispatcher());
 
         // Transform the combined Future into a Future that returns the cohort actor path from
         // the ReadyTransactionReply. That's the end result of the ready operation.
@@ -152,7 +152,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
                             serializedReadyReply.getClass()));
                 }
             }
-        }, TransactionProxy.SAME_FAILURE_TRANSFORMER, actorContext.getActorSystem().dispatcher());
+        }, TransactionProxy.SAME_FAILURE_TRANSFORMER, actorContext.getClientDispatcher());
     }
 
     @Override
@@ -198,7 +198,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
 
             Future<Iterable<Object>> combinedFutures = akka.dispatch.Futures.sequence(
                     Lists.newArrayList(recordedOperationFutures),
-                    actorContext.getActorSystem().dispatcher());
+                    actorContext.getClientDispatcher());
 
             OnComplete<Iterable<Object>> onComplete = new OnComplete<Iterable<Object>>() {
                 @Override
@@ -216,7 +216,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
                 }
             };
 
-            combinedFutures.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
+            combinedFutures.onComplete(onComplete, actorContext.getClientDispatcher());
         }
 
     }
@@ -255,7 +255,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
 
         Future<Object> readFuture = executeOperationAsync(new ReadData(path));
 
-        readFuture.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
+        readFuture.onComplete(onComplete, actorContext.getClientDispatcher());
     }
 
     @Override
@@ -280,7 +280,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
 
             Future<Iterable<Object>> combinedFutures = akka.dispatch.Futures.sequence(
                     Lists.newArrayList(recordedOperationFutures),
-                    actorContext.getActorSystem().dispatcher());
+                    actorContext.getClientDispatcher());
             OnComplete<Iterable<Object>> onComplete = new OnComplete<Iterable<Object>>() {
                 @Override
                 public void onComplete(Throwable failure, Iterable<Object> notUsed)
@@ -297,7 +297,7 @@ final class TransactionContextImpl extends AbstractTransactionContext {
                 }
             };
 
-            combinedFutures.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
+            combinedFutures.onComplete(onComplete, actorContext.getClientDispatcher());
         }
     }
 
@@ -332,6 +332,6 @@ final class TransactionContextImpl extends AbstractTransactionContext {
 
         Future<Object> future = executeOperationAsync(new DataExists(path));
 
-        future.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
+        future.onComplete(onComplete, actorContext.getClientDispatcher());
     }
 }
index 5bc53442aeff04aa43c299a49890b3ecfe70b974..d63ec8010dc714adc71c951bf7fd0a65937a4ce7 100644 (file)
@@ -484,7 +484,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                         newTxFutureCallback.setPrimaryShard(primaryShard);
                     }
                 }
-            }, actorContext.getActorSystem().dispatcher());
+            }, actorContext.getClientDispatcher());
         }
 
         return txFutureCallback;
@@ -601,7 +601,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                             TransactionProxy.this.transactionType.ordinal(),
                             getTransactionChainId()).toSerializable());
 
-            createTxFuture.onComplete(this, actorContext.getActorSystem().dispatcher());
+            createTxFuture.onComplete(this, actorContext.getClientDispatcher());
         }
 
         @Override
@@ -621,7 +621,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                                 public void run() {
                                     tryCreateTransaction();
                                 }
-                            }, actorContext.getActorSystem().dispatcher());
+                            }, actorContext.getClientDispatcher());
                     return;
                 }
             }
index cb06c898fd1940743c19b1763f2b173ec3dacbfc..26e6318f6d4d14aa5944a909696bbaa8b5f7f207 100644 (file)
@@ -47,6 +47,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import scala.concurrent.Await;
+import scala.concurrent.ExecutionContext;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
 import scala.concurrent.duration.FiniteDuration;
@@ -93,6 +94,7 @@ public class ActorContext {
     private final JmxReporter jmxReporter = JmxReporter.forRegistry(metricRegistry).inDomain(DOMAIN).build();
     private final int transactionOutstandingOperationLimit;
     private final Timeout transactionCommitOperationTimeout;
+    private final Dispatchers dispatchers;
 
     private volatile SchemaContext schemaContext;
 
@@ -111,6 +113,7 @@ public class ActorContext {
         this.configuration = configuration;
         this.datastoreContext = datastoreContext;
         this.txRateLimiter = RateLimiter.create(datastoreContext.getTransactionCreationInitialRateLimit());
+        this.dispatchers = new Dispatchers(actorSystem.dispatchers());
 
         operationDuration = Duration.create(datastoreContext.getOperationTimeoutInSeconds(), TimeUnit.SECONDS);
         operationTimeout = new Timeout(operationDuration);
@@ -127,6 +130,7 @@ public class ActorContext {
 
         transactionOutstandingOperationLimit = new CommonConfig(this.getActorSystem().settings().config()).getMailBoxCapacity();
         jmxReporter.start();
+
     }
 
     public DatastoreContext getDatastoreContext() {
@@ -200,7 +204,7 @@ public class ActorContext {
                 throw new UnknownMessageException(String.format(
                         "FindPrimary returned unkown response: %s", response));
             }
-        }, FIND_PRIMARY_FAILURE_TRANSFORMER, getActorSystem().dispatcher());
+        }, FIND_PRIMARY_FAILURE_TRANSFORMER, getClientDispatcher());
     }
 
     /**
@@ -251,7 +255,7 @@ public class ActorContext {
                 throw new UnknownMessageException(String.format(
                         "FindLocalShard returned unkown response: %s", response));
             }
-        }, getActorSystem().dispatcher());
+        }, getClientDispatcher());
     }
 
     private String findPrimaryPathOrNull(String shardName) {
@@ -514,5 +518,17 @@ public class ActorContext {
         return transactionCommitOperationTimeout;
     }
 
+    /**
+     * An akka dispatcher that is meant to be used when processing ask Futures which were triggered by client
+     * code on the datastore
+     * @return
+     */
+    public ExecutionContext getClientDispatcher() {
+        return this.dispatchers.getDispatcher(Dispatchers.DispatcherType.Client);
+    }
+
+    public String getNotificationDispatcherPath(){
+        return this.dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Notification);
+    }
 
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/Dispatchers.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/Dispatchers.java
new file mode 100644 (file)
index 0000000..8de8a9d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.cluster.datastore.utils;
+
+import com.google.common.base.Preconditions;
+import scala.concurrent.ExecutionContext;
+
+public class Dispatchers {
+    public static final String DEFAULT_DISPATCHER_PATH = "akka.actor.default-dispatcher";
+    public static final String CLIENT_DISPATCHER_PATH = "client-dispatcher";
+    public static final String TXN_DISPATCHER_PATH = "txn-dispatcher";
+    public static final String SHARD_DISPATCHER_PATH = "shard-dispatcher";
+    public static final String NOTIFICATION_DISPATCHER_PATH = "notification-dispatcher";
+
+    private final akka.dispatch.Dispatchers dispatchers;
+
+    public static enum DispatcherType {
+        Client(CLIENT_DISPATCHER_PATH),
+        Transaction(TXN_DISPATCHER_PATH),
+        Shard(SHARD_DISPATCHER_PATH),
+        Notification(NOTIFICATION_DISPATCHER_PATH);
+
+        private final String path;
+        private DispatcherType(String path){
+            this.path = path;
+        }
+        private String path(akka.dispatch.Dispatchers dispatchers){
+            if(dispatchers.hasDispatcher(path)){
+                return path;
+            }
+            return DEFAULT_DISPATCHER_PATH;
+        }
+
+        private ExecutionContext dispatcher(akka.dispatch.Dispatchers dispatchers){
+            if(dispatchers.hasDispatcher(path)){
+                return dispatchers.lookup(path);
+            }
+            return dispatchers.defaultGlobalDispatcher();
+        }
+    }
+
+    public Dispatchers(akka.dispatch.Dispatchers dispatchers){
+        Preconditions.checkNotNull(dispatchers, "dispatchers should not be null");
+        this.dispatchers = dispatchers;
+    }
+
+    public ExecutionContext getDispatcher(DispatcherType dispatcherType){
+        return dispatcherType.dispatcher(this.dispatchers);
+    }
+
+    public String getDispatcherPath(DispatcherType dispatcherType){
+        return dispatcherType.path(this.dispatchers);
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/MessageTracker.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/MessageTracker.java
new file mode 100644 (file)
index 0000000..2757d2f
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.cluster.datastore.utils;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * MessageTracker is a diagnostic utility class to be used for figuring out why a certain message which was
+ * expected to arrive in a given time interval does not arrive. It attempts to keep track of all the messages that
+ * received between the arrival of two instances of the same message and the amount of time it took to process each
+ * of those messages.
+ * <br/>
+ * Usage of the API is as follows,
+ * <pre>
+ *
+ *      // Track the Foo class, Here we expect to see a message of type Foo come in every 10 millis
+ *     MessageTracker tracker = new MessageTracker(Foo.class, 10);
+ *
+ *     // Begin the tracking process. If this is not called then calling received and done on the resultant Context
+ *     // will do nothing
+ *     tracker.begin();
+ *
+ *     .....
+ *
+ *     MessageTracker.Context context = tracker.received(message);
+ *
+ *     if(context.error().isPresent()){
+ *         LOG.error("{}", context.error().get());
+ *     }
+ *
+ *     // Some custom processing
+ *     process(message);
+ *
+ *     context.done();
+ *
+ * </pre>
+ */
+public class MessageTracker {
+
+    private static final Context NO_OP_CONTEXT = new NoOpContext();
+
+    private final Class expectedMessageClass;
+
+    private final long expectedArrivalInterval;
+
+    private final List<MessageProcessingTime> messagesSinceLastExpectedMessage = new LinkedList<>();
+
+    private Stopwatch expectedMessageWatch;
+
+    private boolean enabled = false;
+
+    private Object lastExpectedMessage;
+
+    private Object currentMessage;
+
+    private final CurrentMessageContext currentMessageContext = new CurrentMessageContext();
+
+    /**
+     *
+     * @param expectedMessageClass The class of the message to track
+     * @param expectedArrivalIntervalInMillis The expected arrival interval between two instances of the expected
+     *                                        message
+     */
+    public MessageTracker(Class expectedMessageClass, long expectedArrivalIntervalInMillis){
+        this.expectedMessageClass = expectedMessageClass;
+        this.expectedArrivalInterval = expectedArrivalIntervalInMillis;
+    }
+
+    public void begin(){
+        if(enabled) {
+            return;
+        }
+        enabled = true;
+        expectedMessageWatch = Stopwatch.createStarted();
+    }
+
+    public Context received(Object message){
+        if(!enabled) {
+            return NO_OP_CONTEXT;
+        }
+        this.currentMessage = message;
+        if(expectedMessageClass.isInstance(message)){
+            long actualElapsedTime = expectedMessageWatch.elapsed(TimeUnit.MILLISECONDS);
+            if(actualElapsedTime > expectedArrivalInterval){
+                return new ErrorContext(message, Optional.of(new FailedExpectation(lastExpectedMessage, message,
+                        ImmutableList.copyOf(messagesSinceLastExpectedMessage), expectedArrivalInterval,
+                        actualElapsedTime)));
+            }
+            this.lastExpectedMessage = message;
+            this.messagesSinceLastExpectedMessage.clear();
+        }
+
+        currentMessageContext.reset();
+        return currentMessageContext;
+    }
+
+    private void processed(Object message, long messageElapseTimeInNanos){
+        if(!enabled) {
+            return;
+        }
+        if(!expectedMessageClass.isInstance(message)){
+            this.messagesSinceLastExpectedMessage.add(new MessageProcessingTime(message.getClass(), messageElapseTimeInNanos));
+        }
+    }
+
+    public List<MessageProcessingTime> getMessagesSinceLastExpectedMessage(){
+        return ImmutableList.copyOf(this.messagesSinceLastExpectedMessage);
+    }
+
+    public static class MessageProcessingTime {
+        private final Class messageClass;
+        private final long elapsedTimeInNanos;
+
+        MessageProcessingTime(Class messageClass, long elapsedTimeInNanos){
+            this.messageClass = messageClass;
+            this.elapsedTimeInNanos = elapsedTimeInNanos;
+        }
+
+        @Override
+        public String toString() {
+            return "MessageProcessingTime{" +
+                    "messageClass=" + messageClass.getSimpleName() +
+                    ", elapsedTimeInMillis=" + TimeUnit.NANOSECONDS.toMillis(elapsedTimeInNanos) +
+                    '}';
+        }
+
+        public Class getMessageClass() {
+            return messageClass;
+        }
+
+        public long getElapsedTimeInNanos() {
+            return elapsedTimeInNanos;
+        }
+    }
+
+    public interface Error {
+        Object getLastExpectedMessage();
+        Object getCurrentExpectedMessage();
+        List<MessageProcessingTime> getMessageProcessingTimesSinceLastExpectedMessage();
+    }
+
+    private class FailedExpectation implements Error {
+
+        private final Object lastExpectedMessage;
+        private final Object currentExpectedMessage;
+        private final List<MessageProcessingTime> messagesSinceLastExpectedMessage;
+        private final long expectedTimeInMillis;
+        private final long actualTimeInMillis;
+
+        public FailedExpectation(Object lastExpectedMessage, Object message, List<MessageProcessingTime> messagesSinceLastExpectedMessage, long expectedTimeInMillis, long actualTimeInMillis) {
+            this.lastExpectedMessage = lastExpectedMessage;
+            this.currentExpectedMessage = message;
+            this.messagesSinceLastExpectedMessage = messagesSinceLastExpectedMessage;
+            this.expectedTimeInMillis = expectedTimeInMillis;
+            this.actualTimeInMillis = actualTimeInMillis;
+        }
+
+        public Object getLastExpectedMessage() {
+            return lastExpectedMessage;
+        }
+
+        public Object getCurrentExpectedMessage() {
+            return currentExpectedMessage;
+        }
+
+        public List<MessageProcessingTime>  getMessageProcessingTimesSinceLastExpectedMessage() {
+            return messagesSinceLastExpectedMessage;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("\n> Last Expected Message = " + lastExpectedMessage);
+            builder.append("\n> Current Expected Message = " + currentExpectedMessage);
+            builder.append("\n> Expected time in between messages = " + expectedTimeInMillis);
+            builder.append("\n> Actual time in between messages = " + actualTimeInMillis);
+            for (MessageProcessingTime time : messagesSinceLastExpectedMessage) {
+                builder.append("\n\t> ").append(time.toString());
+            }
+            return builder.toString();
+        }
+
+    }
+
+    public interface Context {
+        Context done();
+        Optional<? extends Error> error();
+    }
+
+    private static class NoOpContext implements Context {
+
+        @Override
+        public Context done() {
+            return this;
+        }
+
+        @Override
+        public Optional<Error> error() {
+            return Optional.absent();
+        }
+    }
+
+    private class CurrentMessageContext implements Context {
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        boolean done = true;
+
+        public void reset(){
+            Preconditions.checkState(done);
+            done = false;
+            stopwatch.reset().start();
+        }
+
+        @Override
+        public Context done() {
+            processed(currentMessage, stopwatch.elapsed(TimeUnit.NANOSECONDS));
+            done = true;
+            return this;
+        }
+
+        @Override
+        public Optional<? extends Error> error() {
+            return Optional.absent();
+        }
+    }
+
+    private class ErrorContext implements Context {
+        Object message;
+        private final Optional<? extends Error> error;
+        Stopwatch stopwatch;
+
+        ErrorContext(Object message, Optional<? extends Error> error){
+            this.message = message;
+            this.error = error;
+            this.stopwatch = Stopwatch.createStarted();
+        }
+
+        @Override
+        public Context done(){
+            processed(message, this.stopwatch.elapsed(TimeUnit.NANOSECONDS));
+            this.stopwatch.stop();
+            return this;
+        }
+
+        @Override
+        public Optional<? extends Error> error() {
+            return error;
+        }
+    }
+}
index 58aec30a8470035bfd7111c5b4c5badebf26b401..f6c8f07f6b18cd51b5b7ba72ae77a693a3885ec0 100644 (file)
@@ -36,6 +36,7 @@ import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply;
 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
+import org.opendaylight.controller.cluster.datastore.utils.Dispatchers;
 import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor;
 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
@@ -193,10 +194,12 @@ public class DataChangeListenerRegistrationProxyTest extends AbstractActorTest {
             doReturn(mockActor).when(mockActorSystem).actorOf(any(Props.class));
             ExecutionContextExecutor executor = ExecutionContexts.fromExecutor(
                     MoreExecutors.sameThreadExecutor());
-            doReturn(executor).when(mockActorSystem).dispatcher();
+
 
             ActorContext actorContext = mock(ActorContext.class);
 
+            doReturn(executor).when(actorContext).getClientDispatcher();
+
             String shardName = "shard-1";
             final DataChangeListenerRegistrationProxy proxy = new DataChangeListenerRegistrationProxy(
                     shardName, actorContext, mockListener);
@@ -227,7 +230,9 @@ public class DataChangeListenerRegistrationProxyTest extends AbstractActorTest {
                     shardName, actorContext, mockListener);
 
             doReturn(DatastoreContext.newBuilder().build()).when(actorContext).getDatastoreContext();
+            doReturn(getSystem().dispatchers().defaultGlobalDispatcher()).when(actorContext).getClientDispatcher();
             doReturn(getSystem()).when(actorContext).getActorSystem();
+            doReturn(Dispatchers.DEFAULT_DISPATCHER_PATH).when(actorContext).getNotificationDispatcherPath();
             doReturn(getSystem().actorSelection(getRef().path())).
                     when(actorContext).actorSelection(getRef().path());
             doReturn(duration("5 seconds")).when(actorContext).getOperationDuration();
index 3e8982371808d3eb2228494ababcc64dd04c844e..d3a3a8fc2df812b88ffc500c71e17d224189b541 100644 (file)
@@ -28,7 +28,7 @@ public class DatastoreContextTest {
         assertEquals(DatastoreContext.DEFAULT_SHARD_LEADER_ELECTION_TIMEOUT, build.getShardLeaderElectionTimeout());
         assertEquals(DatastoreContext.DEFAULT_PERSISTENT, build.isPersistent());
         assertEquals(DatastoreContext.DEFAULT_CONFIGURATION_READER, build.getConfigurationReader());
-        assertEquals(DatastoreContext.DEFAULT_ISOLATED_LEADER_CHECK_INTERVAL_IN_MILLIS, build.getShardRaftConfig().getIsolatedCheckInterval().length());
+        assertEquals(DatastoreContext.DEFAULT_ISOLATED_LEADER_CHECK_INTERVAL_IN_MILLIS, build.getShardRaftConfig().getIsolatedCheckIntervalInMillis());
         assertEquals(DatastoreContext.DEFAULT_SHARD_SNAPSHOT_DATA_THRESHOLD_PERCENTAGE, build.getShardRaftConfig().getSnapshotDataThresholdPercentage());
         assertEquals(DatastoreContext.DEFAULT_SHARD_ELECTION_TIMEOUT_FACTOR, build.getShardRaftConfig().getElectionTimeoutFactor());
         assertEquals(DatastoreContext.DEFAULT_TX_CREATION_INITIAL_RATE_LIMIT, build.getTransactionCreationInitialRateLimit());
index d2396e0524f340844ea5f7c0e35dfd6cad0b4806..0a2a0d1bc0595a8932f2e2ee3ab27c6b8f422855 100644 (file)
@@ -66,12 +66,13 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
         MockitoAnnotations.initMocks(this);
 
         doReturn(getSystem()).when(actorContext).getActorSystem();
+        doReturn(getSystem().dispatchers().defaultGlobalDispatcher()).when(actorContext).getClientDispatcher();
         doReturn(datastoreContext).when(actorContext).getDatastoreContext();
         doReturn(100).when(datastoreContext).getShardTransactionCommitTimeoutInSeconds();
         doReturn(commitTimer).when(actorContext).getOperationTimer("commit");
         doReturn(commitTimerContext).when(commitTimer).time();
         doReturn(commitSnapshot).when(commitTimer).getSnapshot();
-        doReturn(TimeUnit.MILLISECONDS.toNanos(2000) * 1.0).when(commitSnapshot).get98thPercentile();
+        doReturn(TimeUnit.MILLISECONDS.toNanos(2000) * 1.0).when(commitSnapshot).get95thPercentile();
         doReturn(10.0).when(actorContext).getTxCreationLimit();
     }
 
index 7ce41a4db1304bd84cbdf2b7e02ce0fd4363e828..fa2f9187d6059f1585a1475531556d8563db3c5a 100644 (file)
@@ -129,6 +129,7 @@ public class TransactionProxyTest {
         DatastoreContext dataStoreContext = DatastoreContext.newBuilder().operationTimeoutInSeconds(2).build();
 
         doReturn(getSystem()).when(mockActorContext).getActorSystem();
+        doReturn(getSystem().dispatchers().defaultGlobalDispatcher()).when(mockActorContext).getClientDispatcher();
         doReturn(memberName).when(mockActorContext).getCurrentMemberName();
         doReturn(schemaContext).when(mockActorContext).getSchemaContext();
         doReturn(mockClusterWrapper).when(mockActorContext).getClusterWrapper();
index eae46da2eee53bd4b2cf5ee7d2cb823e0111b6be..3c6a0cef5c605fbb23e3c9501676f67d95805e9d 100644 (file)
@@ -1,17 +1,20 @@
 package org.opendaylight.controller.cluster.datastore.utils;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
+import akka.actor.ActorSystem;
 import akka.actor.Address;
 import akka.actor.Props;
 import akka.actor.UntypedActor;
 import akka.japi.Creator;
 import akka.testkit.JavaTestKit;
 import com.google.common.base.Optional;
+import com.typesafe.config.ConfigFactory;
 import java.util.concurrent.TimeUnit;
 import org.apache.commons.lang.time.StopWatch;
 import org.junit.Test;
@@ -299,4 +302,41 @@ public class ActorContextTest extends AbstractActorTest{
 
         assertTrue("did not take as much time as expected", watch.getTime() > 1000);
     }
+
+    @Test
+    public void testClientDispatcherIsGlobalDispatcher(){
+
+        DatastoreContext mockDataStoreContext = mock(DatastoreContext.class);
+
+        doReturn(155L).when(mockDataStoreContext).getTransactionCreationInitialRateLimit();
+        doReturn("config").when(mockDataStoreContext).getDataStoreType();
+
+        ActorContext actorContext =
+                new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class),
+                        mock(Configuration.class), mockDataStoreContext);
+
+        assertEquals(getSystem().dispatchers().defaultGlobalDispatcher(), actorContext.getClientDispatcher());
+
+    }
+
+    @Test
+    public void testClientDispatcherIsNotGlobalDispatcher(){
+
+        DatastoreContext mockDataStoreContext = mock(DatastoreContext.class);
+
+        doReturn(155L).when(mockDataStoreContext).getTransactionCreationInitialRateLimit();
+        doReturn("config").when(mockDataStoreContext).getDataStoreType();
+
+        ActorSystem actorSystem = ActorSystem.create("with-custom-dispatchers", ConfigFactory.load("application-with-custom-dispatchers.conf"));
+
+        ActorContext actorContext =
+                new ActorContext(actorSystem, mock(ActorRef.class), mock(ClusterWrapper.class),
+                        mock(Configuration.class), mockDataStoreContext);
+
+        assertNotEquals(actorSystem.dispatchers().defaultGlobalDispatcher(), actorContext.getClientDispatcher());
+
+        actorSystem.shutdown();
+
+    }
+
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/DispatchersTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/DispatchersTest.java
new file mode 100644 (file)
index 0000000..85a0cac
--- /dev/null
@@ -0,0 +1,81 @@
+package org.opendaylight.controller.cluster.datastore.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import akka.dispatch.MessageDispatcher;
+import org.junit.Test;
+
+public class DispatchersTest {
+
+    @Test
+    public void testGetDefaultDispatcherPath(){
+        akka.dispatch.Dispatchers mockDispatchers = mock(akka.dispatch.Dispatchers.class);
+        doReturn(false).when(mockDispatchers).hasDispatcher(anyString());
+        Dispatchers dispatchers = new Dispatchers(mockDispatchers);
+
+        for(Dispatchers.DispatcherType type : Dispatchers.DispatcherType.values()) {
+            assertEquals(Dispatchers.DEFAULT_DISPATCHER_PATH,
+                    dispatchers.getDispatcherPath(type));
+        }
+
+    }
+
+    @Test
+    public void testGetDefaultDispatcher(){
+        akka.dispatch.Dispatchers mockDispatchers = mock(akka.dispatch.Dispatchers.class);
+        MessageDispatcher mockGlobalDispatcher = mock(MessageDispatcher.class);
+        doReturn(false).when(mockDispatchers).hasDispatcher(anyString());
+        doReturn(mockGlobalDispatcher).when(mockDispatchers).defaultGlobalDispatcher();
+        Dispatchers dispatchers = new Dispatchers(mockDispatchers);
+
+        for(Dispatchers.DispatcherType type : Dispatchers.DispatcherType.values()) {
+            assertEquals(mockGlobalDispatcher,
+                    dispatchers.getDispatcher(type));
+        }
+
+    }
+
+    @Test
+    public void testGetDispatcherPath(){
+        akka.dispatch.Dispatchers mockDispatchers = mock(akka.dispatch.Dispatchers.class);
+        doReturn(true).when(mockDispatchers).hasDispatcher(anyString());
+        Dispatchers dispatchers = new Dispatchers(mockDispatchers);
+
+        assertEquals(Dispatchers.CLIENT_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Client));
+
+        assertEquals(Dispatchers.TXN_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Transaction));
+
+        assertEquals(Dispatchers.SHARD_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Shard));
+
+        assertEquals(Dispatchers.NOTIFICATION_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Notification));
+
+    }
+
+    @Test
+    public void testGetDispatcher(){
+        akka.dispatch.Dispatchers mockDispatchers = mock(akka.dispatch.Dispatchers.class);
+        MessageDispatcher mockDispatcher = mock(MessageDispatcher.class);
+        doReturn(true).when(mockDispatchers).hasDispatcher(anyString());
+        doReturn(mockDispatcher).when(mockDispatchers).lookup(anyString());
+        Dispatchers dispatchers = new Dispatchers(mockDispatchers);
+
+        assertEquals(Dispatchers.CLIENT_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Client));
+
+        assertEquals(Dispatchers.TXN_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Transaction));
+
+        assertEquals(Dispatchers.SHARD_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Shard));
+
+        assertEquals(Dispatchers.NOTIFICATION_DISPATCHER_PATH,
+                dispatchers.getDispatcherPath(Dispatchers.DispatcherType.Notification));
+
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MessageTrackerTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MessageTrackerTest.java
new file mode 100644 (file)
index 0000000..a125b49
--- /dev/null
@@ -0,0 +1,188 @@
+package org.opendaylight.controller.cluster.datastore.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import com.google.common.util.concurrent.Uninterruptibles;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MessageTrackerTest {
+
+    private final Logger LOG = LoggerFactory.getLogger(getClass());
+
+    private class Foo {}
+
+    @Test
+    public void testNoTracking(){
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+
+        MessageTracker.Context context1 = messageTracker.received(new Foo());
+        context1.done();
+
+        Uninterruptibles.sleepUninterruptibly(20, TimeUnit.MILLISECONDS);
+
+        MessageTracker.Context context2 = messageTracker.received(new Foo());
+        context2.done();
+
+    }
+
+    @Test
+    public void testFailedExpectationOnTracking(){
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+        messageTracker.begin();
+
+        MessageTracker.Context context1 = messageTracker.received(new Foo());
+        context1.done();
+
+        Uninterruptibles.sleepUninterruptibly(20, TimeUnit.MILLISECONDS);
+
+        MessageTracker.Context context2 = messageTracker.received(new Foo());
+        Assert.assertEquals(true, context2.error().isPresent());
+        Assert.assertEquals(0, context2.error().get().getMessageProcessingTimesSinceLastExpectedMessage().size());
+
+    }
+
+    @Test
+    public void testFailedExpectationOnTrackingWithMessagesInBetween(){
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+        messageTracker.begin();
+
+        MessageTracker.Context context1 = messageTracker.received(new Foo());
+        context1.done();
+
+        messageTracker.received("A").done();
+        messageTracker.received(Long.valueOf(10)).done();
+        MessageTracker.Context c = messageTracker.received(Integer.valueOf(100));
+
+        Uninterruptibles.sleepUninterruptibly(20, TimeUnit.MILLISECONDS);
+
+        c.done();
+
+        MessageTracker.Context context2 = messageTracker.received(new Foo());
+
+        Assert.assertEquals(true, context2.error().isPresent());
+
+        MessageTracker.Error error = context2.error().get();
+
+        List<MessageTracker.MessageProcessingTime> messageProcessingTimes =
+                error.getMessageProcessingTimesSinceLastExpectedMessage();
+
+        Assert.assertEquals(3, messageProcessingTimes.size());
+
+        Assert.assertEquals(String.class, messageProcessingTimes.get(0).getMessageClass());
+        Assert.assertEquals(Long.class, messageProcessingTimes.get(1).getMessageClass());
+        Assert.assertEquals(Integer.class, messageProcessingTimes.get(2).getMessageClass());
+        Assert.assertTrue(messageProcessingTimes.get(2).getElapsedTimeInNanos() > TimeUnit.MILLISECONDS.toNanos(10));
+        Assert.assertEquals(Foo.class, error.getLastExpectedMessage().getClass());
+        Assert.assertEquals(Foo.class, error.getCurrentExpectedMessage().getClass());
+
+        LOG.error("An error occurred : {}" , error);
+
+    }
+
+
+    @Test
+    public void testMetExpectationOnTracking(){
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+        messageTracker.begin();
+
+        MessageTracker.Context context1 = messageTracker.received(new Foo());
+        context1.done();
+
+        Uninterruptibles.sleepUninterruptibly(1, TimeUnit.MILLISECONDS);
+
+        MessageTracker.Context context2 = messageTracker.received(new Foo());
+        Assert.assertEquals(false, context2.error().isPresent());
+
+    }
+
+    @Test
+    public void testIllegalStateExceptionWhenDoneIsNotCalledWhileTracking(){
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+        messageTracker.begin();
+
+        messageTracker.received(new Foo());
+
+        try {
+            messageTracker.received(new Foo());
+            fail("Expected an IllegalStateException");
+        } catch (IllegalStateException e){
+
+        }
+    }
+
+    @Test
+    public void testNoIllegalStateExceptionWhenDoneIsNotCalledWhileNotTracking(){
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+
+        messageTracker.received(new Foo());
+        messageTracker.received(new Foo());
+    }
+
+    @Test
+    public void testDelayInFirstExpectedMessageArrival(){
+
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+        messageTracker.begin();
+
+        Uninterruptibles.sleepUninterruptibly(20, TimeUnit.MILLISECONDS);
+
+        MessageTracker.Context context = messageTracker.received(new Foo());
+
+        Assert.assertEquals(true, context.error().isPresent());
+
+        MessageTracker.Error error = context.error().get();
+
+        Assert.assertEquals(null, error.getLastExpectedMessage());
+        Assert.assertEquals(Foo.class, error.getCurrentExpectedMessage().getClass());
+
+        String errorString = error.toString();
+        Assert.assertTrue(errorString.contains("Last Expected Message = null"));
+
+        LOG.error("An error occurred : {}", error);
+    }
+
+    @Test
+    public void testCallingBeginDoesNotResetWatch(){
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+        messageTracker.begin();
+
+        Uninterruptibles.sleepUninterruptibly(20, TimeUnit.MILLISECONDS);
+
+        messageTracker.begin();
+
+        MessageTracker.Context context = messageTracker.received(new Foo());
+
+        Assert.assertEquals(true, context.error().isPresent());
+
+    }
+
+    @Test
+    public void testMessagesSinceLastExpectedMessage(){
+
+        MessageTracker messageTracker = new MessageTracker(Foo.class, 10);
+        messageTracker.begin();
+
+        MessageTracker.Context context1 = messageTracker.received(Integer.valueOf(45)).done();
+
+        Assert.assertEquals(false, context1.error().isPresent());
+
+        MessageTracker.Context context2 = messageTracker.received(Long.valueOf(45)).done();
+
+        Assert.assertEquals(false, context2.error().isPresent());
+
+        List<MessageTracker.MessageProcessingTime> processingTimeList =
+                messageTracker.getMessagesSinceLastExpectedMessage();
+
+        Assert.assertEquals(2, processingTimeList.size());
+
+        assertEquals(Integer.class, processingTimeList.get(0).getMessageClass());
+        assertEquals(Long.class, processingTimeList.get(1).getMessageClass());
+
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application-with-custom-dispatchers.conf b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application-with-custom-dispatchers.conf
new file mode 100644 (file)
index 0000000..32c55a6
--- /dev/null
@@ -0,0 +1,116 @@
+akka {
+    persistence.snapshot-store.plugin = "in-memory-snapshot-store"
+    persistence.journal.plugin = "in-memory-journal"
+
+    loggers = ["akka.testkit.TestEventListener", "akka.event.slf4j.Slf4jLogger"]
+
+    actor {
+         serializers {
+                  java = "akka.serialization.JavaSerializer"
+                  proto = "akka.remote.serialization.ProtobufSerializer"
+         }
+
+        serialization-bindings {
+            "org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification" = java
+            "com.google.protobuf.Message" = proto
+
+        }
+    }
+}
+
+in-memory-journal {
+    class = "org.opendaylight.controller.cluster.datastore.utils.InMemoryJournal"
+}
+
+in-memory-snapshot-store {
+  # Class name of the plugin.
+  class = "org.opendaylight.controller.cluster.datastore.utils.InMemorySnapshotStore"
+  # Dispatcher for the plugin actor.
+  plugin-dispatcher = "akka.persistence.dispatchers.default-plugin-dispatcher"
+}
+
+bounded-mailbox {
+  mailbox-type = "org.opendaylight.controller.cluster.common.actor.MeteredBoundedMailbox"
+  mailbox-capacity = 1000
+  mailbox-push-timeout-time = 100ms
+}
+
+client-dispatcher {
+  # Dispatcher is the name of the event-based dispatcher
+  type = Dispatcher
+  # What kind of ExecutionService to use
+  executor = "fork-join-executor"
+  # Configuration for the fork join pool
+  fork-join-executor {
+    # Min number of threads to cap factor-based parallelism number to
+    parallelism-min = 2
+    # Parallelism (threads) ... ceil(available processors * factor)
+    parallelism-factor = 2.0
+    # Max number of threads to cap factor-based parallelism number to
+    parallelism-max = 10
+  }
+  # Throughput defines the maximum number of messages to be
+  # processed per actor before the thread jumps to the next actor.
+  # Set to 1 for as fair as possible.
+  throughput = 100
+}
+
+transaction-dispatcher {
+  # Dispatcher is the name of the event-based dispatcher
+  type = Dispatcher
+  # What kind of ExecutionService to use
+  executor = "fork-join-executor"
+  # Configuration for the fork join pool
+  fork-join-executor {
+    # Min number of threads to cap factor-based parallelism number to
+    parallelism-min = 2
+    # Parallelism (threads) ... ceil(available processors * factor)
+    parallelism-factor = 2.0
+    # Max number of threads to cap factor-based parallelism number to
+    parallelism-max = 10
+  }
+  # Throughput defines the maximum number of messages to be
+  # processed per actor before the thread jumps to the next actor.
+  # Set to 1 for as fair as possible.
+  throughput = 100
+}
+
+shard-dispatcher {
+  # Dispatcher is the name of the event-based dispatcher
+  type = Dispatcher
+  # What kind of ExecutionService to use
+  executor = "fork-join-executor"
+  # Configuration for the fork join pool
+  fork-join-executor {
+    # Min number of threads to cap factor-based parallelism number to
+    parallelism-min = 2
+    # Parallelism (threads) ... ceil(available processors * factor)
+    parallelism-factor = 2.0
+    # Max number of threads to cap factor-based parallelism number to
+    parallelism-max = 10
+  }
+  # Throughput defines the maximum number of messages to be
+  # processed per actor before the thread jumps to the next actor.
+  # Set to 1 for as fair as possible.
+  throughput = 100
+}
+
+notification-dispatcher {
+  # Dispatcher is the name of the event-based dispatcher
+  type = Dispatcher
+  # What kind of ExecutionService to use
+  executor = "fork-join-executor"
+  # Configuration for the fork join pool
+  fork-join-executor {
+    # Min number of threads to cap factor-based parallelism number to
+    parallelism-min = 2
+    # Parallelism (threads) ... ceil(available processors * factor)
+    parallelism-factor = 2.0
+    # Max number of threads to cap factor-based parallelism number to
+    parallelism-max = 10
+  }
+  # Throughput defines the maximum number of messages to be
+  # processed per actor before the thread jumps to the next actor.
+  # Set to 1 for as fair as possible.
+  throughput = 100
+}
\ No newline at end of file
index 0302a7d920bc248a2566569dbaa7680f286df1fc..89fca50354a04f44983b2e5e8126209a3aae4a34 100644 (file)
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
     </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-test-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
index 7370ebee7fe1ae3c0ac3b60ddd4337ffad53e66f..f404c0637f4cfe5ac49fb4fa5001ad1c71aa563d 100644 (file)
@@ -8,17 +8,19 @@ package org.opendaylight.controller.md.sal.dom.api;
 
 import com.google.common.base.Preconditions;
 import java.io.Serializable;
+import java.util.Iterator;
 import javax.annotation.Nonnull;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.concepts.Path;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 
 /**
  * A unique identifier for a particular subtree. It is composed of the logical
  * data store type and the instance identifier of the root node.
  */
-public final class DOMDataTreeIdentifier implements Immutable, Path<DOMDataTreeIdentifier>, Serializable {
+public final class DOMDataTreeIdentifier implements Immutable, Path<DOMDataTreeIdentifier>, Serializable, Comparable<DOMDataTreeIdentifier> {
     private static final long serialVersionUID = 1L;
     private final YangInstanceIdentifier rootIdentifier;
     private final LogicalDatastoreType datastoreType;
@@ -74,4 +76,30 @@ public final class DOMDataTreeIdentifier implements Immutable, Path<DOMDataTreeI
         }
         return rootIdentifier.equals(other.rootIdentifier);
     }
+
+    @Override
+    public int compareTo(final DOMDataTreeIdentifier o) {
+        int i = datastoreType.compareTo(o.datastoreType);
+        if (i != 0) {
+            return i;
+        }
+
+        final Iterator<PathArgument> mi = rootIdentifier.getPathArguments().iterator();
+        final Iterator<PathArgument> oi = o.rootIdentifier.getPathArguments().iterator();
+
+        while (mi.hasNext()) {
+            if (!oi.hasNext()) {
+                return 1;
+            }
+
+            final PathArgument ma = mi.next();
+            final PathArgument oa = oi.next();
+            i = ma.compareTo(oa);
+            if (i != 0) {
+                return i;
+            }
+        }
+
+        return oi.hasNext() ? -1 : 0;
+    }
 }
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeInaccessibleException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeInaccessibleException.java
new file mode 100644 (file)
index 0000000..eea1be5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import com.google.common.base.Preconditions;
+
+
+/**
+ * Failure reported when a data tree is no longer accessible.
+ */
+public class DOMDataTreeInaccessibleException extends DOMDataTreeListeningException {
+    private static final long serialVersionUID = 1L;
+    private final DOMDataTreeIdentifier treeIdentifier;
+
+    public DOMDataTreeInaccessibleException(final DOMDataTreeIdentifier treeIdentifier, final String message) {
+        super(message);
+        this.treeIdentifier = Preconditions.checkNotNull(treeIdentifier);
+    }
+
+    public DOMDataTreeInaccessibleException(final DOMDataTreeIdentifier treeIdentifier, final String message, final Throwable cause) {
+        super(message);
+        this.treeIdentifier = Preconditions.checkNotNull(treeIdentifier);
+    }
+
+    public final DOMDataTreeIdentifier getTreeIdentifier() {
+        return treeIdentifier;
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeListener.java
new file mode 100644 (file)
index 0000000..083cd10
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+
+/**
+ * Interface implemented by data consumers, e.g. processes wanting to act on data
+ * after it has been introduced to the conceptual data tree.
+ */
+public interface DOMDataTreeListener extends EventListener {
+    /**
+     * Invoked whenever one or more registered subtrees change. The logical changes are reported,
+     * as well as the roll up of new state for all subscribed subtrees.
+     *
+     * @param changes The set of changes being reported. Each subscribed subtree may be present
+     *                at most once.
+     * @param subtrees Per-subtree state as visible after the reported changes have been applied.
+     *                 This includes all the subtrees this listener is subscribed to, even those
+     *                 which have not changed.
+     */
+    void onDataTreeChanged(@Nonnull Collection<DataTreeCandidate> changes, @Nonnull Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>> subtrees);
+
+    /**
+     * Invoked when a subtree listening failure occurs. This can be triggered, for example, when
+     * a connection to external subtree source is broken. The listener will not receive any other
+     * callbacks, but its registration still needs to be closed to prevent resource leak.
+     *
+     * @param cause Collection of failure causes, may not be null or empty.
+     */
+    void onDataTreeFailed(@Nonnull Collection<DOMDataTreeListeningException> causes);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeListeningException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeListeningException.java
new file mode 100644 (file)
index 0000000..e0d9b42
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+/**
+ * Base exception for various causes why and {@link DOMDataTreeListener}
+ * may be terminated by the {@link DOMDataTreeService} implementation.
+ */
+public class DOMDataTreeListeningException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public DOMDataTreeListeningException(final String message) {
+        super(message);
+    }
+
+    public DOMDataTreeListeningException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeLoopException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeLoopException.java
new file mode 100644 (file)
index 0000000..8f498a8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Exception thrown when a loop is detected in the way {@link DOMDataTreeListener}
+ * and {@link DOMDataTreeProducer} instances would be connected.
+ */
+public class DOMDataTreeLoopException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public DOMDataTreeLoopException(final @Nonnull String message) {
+        super(message);
+    }
+
+    public DOMDataTreeLoopException(final @Nonnull String message, final @Nonnull Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducer.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducer.java
new file mode 100644 (file)
index 0000000..cbfa012
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+
+/**
+ * A data producer context. It allows transactions to be submitted to the subtrees
+ * specified at instantiation time. At any given time there may be a single transaction
+ * open. It needs to be either submitted or cancelled before another one can be open.
+ * Once a transaction is submitted, it will proceed to be committed asynchronously.
+ *
+ * Each instance has  an upper bound on the number of transactions which can be in-flight,
+ * once that capacity is exceeded, an attempt to create a new transaction will block
+ * until some transactions complete.
+ *
+ * Each {@link DOMDataTreeProducer} can be in two logical states, bound and unbound,
+ * which define the lifecycle rules for when is it legal to create and submit transactions
+ * in relationship with {@link DOMDataTreeListener} callbacks.
+ *
+ * When a producer is first created, it is unbound. In this state the producer can be
+ * accessed by any application thread to allocate or submit transactions, as long as
+ * the 'single open transaction' rule is maintained. The producer and any transaction
+ * object MUST NOT be accessed, directly or indirectly, from a {@link DOMDataTreeListener}
+ * callback.
+ *
+ * When a producer is referenced in a call to {@link DOMDataTreeService#registerListener(DOMDataTreeListener, java.util.Collection, boolean, java.util.Collection)},
+ * an attempt will be made to bind the producer to the specified {@link DOMDataTreeListener}.
+ * Such an attempt will fail the producer is already bound, or it has an open transaction.
+ * Once bound, the producer can only be accessed from within the {@link DOMDataTreeListener}
+ * callback on that particular instance. Any transaction which is not submitted by the
+ * time the callback returns will be implicitly cancelled. A producer becomes unbound
+ * when the listener it is bound to becomes unregistered.
+ */
+public interface DOMDataTreeProducer extends DOMDataTreeProducerFactory, AutoCloseable {
+    /**
+     * Allocate a new open transaction on this producer. Any and all transactions
+     * previously allocated must have been either submitted or cancelled by the
+     * time this method is invoked.
+     *
+     * @param barrier Indicates whether this transaction should be a barrier. A barrier
+     *                transaction is processed separately from any preceding transactions.
+     *                Non-barrier transactions may be merged and processed in a batch,
+     *                such that any observers see the modifications contained in them as
+     *                if the modifications were made in a single transaction.
+     * @return A new {@link DOMDataWriteTransaction}
+     * @throws {@link IllegalStateException} if a previous transaction was not closed.
+     * @throws {@link IllegalThreadStateException} if the calling thread context does not
+     *         match the lifecycle rules enforced by the producer state (e.g. bound or unbound).
+     *         This exception is thrown on a best effort basis and programs should not rely
+     *         on it for correct operation.
+     */
+    @Nonnull DOMDataWriteTransaction createTransaction(boolean isolated);
+
+    /**
+     * {@inheritDoc}
+     *
+     * When invoked on a {@link DOMDataTreeProducer}, this method has additional restrictions.
+     * There may not be an open transaction from this producer. The method needs to be
+     * invoked in appropriate context, e.g. bound or unbound.
+     *
+     * Specified subtrees must be accessible by this producer. Accessible means they are a subset
+     * of the subtrees specified when the producer is instantiated. The set is further reduced as
+     * child producers are instantiated -- if you create a producer for /a and then a child for
+     * /a/b, /a/b is not accessible from the first producer.
+     *
+     * Once this method returns successfully, this (parent) producer loses the ability to
+     * access the specified paths until the resulting (child) producer is shut down.
+     *
+     * @throws {@link IllegalStateException} if there is an open transaction
+     * @throws {@link IllegalArgumentException} if subtrees contains a subtree which is not
+     *         accessible by this producer
+     * @throws {@link IllegalThreadStateException} if the calling thread context does not
+     *         match the lifecycle rules enforced by the producer state (e.g. bound or unbound).
+     *         This exception is thrown on a best effort basis and programs should not rely
+     *         on it for correct operation.
+     */
+    @Override
+    @Nonnull DOMDataTreeProducer createProducer(@Nonnull Collection<DOMDataTreeIdentifier> subtrees);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws DOMDataTreeProducerBusyException when there is an open transaction.
+     */
+    @Override
+    void close() throws DOMDataTreeProducerException;
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerBusyException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerBusyException.java
new file mode 100644 (file)
index 0000000..a83a5ca
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+/**
+ * Exception indicating that the {@link DOMDataTreeProducer} has an open user
+ * transaction and cannot be closed.
+ */
+public class DOMDataTreeProducerBusyException extends DOMDataTreeProducerException {
+    private static final long serialVersionUID = 1L;
+
+    public DOMDataTreeProducerBusyException(final String message) {
+        super(message);
+    }
+
+    public DOMDataTreeProducerBusyException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerException.java
new file mode 100644 (file)
index 0000000..16c2676
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+/**
+ * Base exception for all exceptions related to {@link DOMDataTreeProducer}s.
+ */
+public class DOMDataTreeProducerException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public DOMDataTreeProducerException(final String message) {
+        super(message);
+    }
+
+    public DOMDataTreeProducerException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerFactory.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeProducerFactory.java
new file mode 100644 (file)
index 0000000..89ac8d1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+
+/**
+ * Base source of {@link DOMDataTreeProducer}s. This interface is usually not used directly,
+ * but rather through one of its sub-interfaces.
+ */
+public interface DOMDataTreeProducerFactory {
+    /**
+     * Create a producer, which is able to access to a set of trees.
+     *
+     * @param subtrees The collection of subtrees the resulting producer should have access to.
+     * @return A {@link DOMDataTreeProducer} instance.
+     * @throws {@link IllegalArgumentException} if subtrees is empty.
+     */
+    @Nonnull DOMDataTreeProducer createProducer(@Nonnull Collection<DOMDataTreeIdentifier> subtrees);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeService.java
new file mode 100644 (file)
index 0000000..21ff44c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * A {@link DOMService} providing access to the conceptual data tree. Interactions
+ * with the data tree are split into data producers and consumers (listeners). Each
+ * of them operate on a set of subtrees, which need to be declared at instantiation time.
+ *
+ * Returned instances are not thread-safe and expected to be used by a single thread
+ * at a time. Furthermore, producers may not be accessed from consumer callbacks
+ * unless they were specified when the listener is registered.
+ *
+ * The service maintains a loop-free topology of producers and consumers. What this means
+ * is that a consumer is not allowed to access a producer, which affects any of the
+ * subtrees it is subscribed to. This restriction is in place to ensure the system does
+ * not go into a feedback loop, where it is impossible to block either a producer or
+ * a consumer without accumulating excess work in the backlog stemming from its previous
+ * activity.
+ */
+public interface DOMDataTreeService extends DOMDataTreeProducerFactory, DOMService {
+    /**
+     * Register a {@link DOMDataTreeListener} instance. Once registered, the listener
+     * will start receiving changes on the selected subtrees. If the listener cannot
+     * keep up with the rate of changes, and allowRxMerges is set to true, this service
+     * is free to merge the changes, so that a smaller number of them will be reported,
+     * possibly hiding some data transitions (like flaps).
+     *
+     * If the listener wants to write into any producer, that producer has to be mentioned
+     * in the call to this method. Those producers will be bound exclusively to the
+     * registration, so that accessing them outside of this listener's callback will trigger
+     * an error. Any producers mentioned must be idle, e.g. they may not have an open
+     * transaction at the time this method is invoked.
+     *
+     * Each listener instance can be registered at most once. Implementations of this
+     * interface have to guarantee that the listener's methods will not be invoked
+     * concurrently from multiple threads.
+     *
+     * @param listener {@link DOMDataTreeListener} that is being registered
+     * @param subtrees Conceptual subtree identifier of subtrees which should be monitored
+     *                 for changes. May not be null or empty.
+     * @param allowRxMerges True if the backend may perform ingress state compression.
+     * @param producers {@link DOMDataTreeProducer} instances to bind to the listener.
+     * @return A listener registration. Once closed, the listener will no longer be
+     *         invoked and the producers will be unbound.
+     * @throws IllegalArgumentException if subtrees is empty or the listener is already bound
+     * @throws DOMDataTreeLoopException if the registration of the listener to the specified
+     *                                  subtrees with specified producers would form a
+     *                                  feedback loop
+     */
+    @Nonnull <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(@Nonnull T listener,
+        @Nonnull Collection<DOMDataTreeIdentifier> subtrees, boolean allowRxMerges, @Nonnull Collection<DOMDataTreeProducer> producers);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShard.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShard.java
new file mode 100644 (file)
index 0000000..e9ef003
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import java.util.EventListener;
+import javax.annotation.Nonnull;
+
+/**
+ * A single shard of the conceptual data tree. This interface defines the basic notifications
+ * a shard can receive. Each shard implementation is expected to also implement some of the
+ * datastore-level APIs. Which interfaces are required depends on the {@link DOMDataTreeShardingService}
+ * implementation.
+ */
+public interface DOMDataTreeShard extends EventListener {
+    /**
+     * Invoked whenever a child is getting attached as a more specific prefix under this shard.
+     *
+     * @param prefix Child's prefix
+     * @param child Child shard
+     */
+    void onChildAttached(@Nonnull DOMDataTreeIdentifier prefix, @Nonnull DOMDataTreeShard child);
+
+    /**
+     * Invoked whenever a child is getting detached as a more specific prefix under this shard.
+     *
+     * @param prefix Child's prefix
+     * @param child Child shard
+     */
+    void onChildDetached(@Nonnull DOMDataTreeIdentifier prefix, @Nonnull DOMDataTreeShard child);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShardingConflictException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShardingConflictException.java
new file mode 100644 (file)
index 0000000..d44316d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Exception thrown when an attempt to attach a conflicting shard to the global
+ * table.
+ */
+public class DOMDataTreeShardingConflictException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public DOMDataTreeShardingConflictException(final @Nonnull String message) {
+        super(message);
+    }
+
+    public DOMDataTreeShardingConflictException(final @Nonnull String message, final @Nonnull Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShardingService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataTreeShardingService.java
new file mode 100644 (file)
index 0000000..c087224
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * A {@link DOMService} providing access to details on how the conceptual data tree
+ * is distributed among providers (also known as shards). Each shard is tied to a
+ * single {@link DOMDataTreeIdentifier}. Based on those data tree identifiers, the
+ * shards are organized in a tree, where there is a logical parent/child relationship.
+ *
+ * It is not allowed to attach two shards to the same data tree identifier, which means
+ * the mapping of each piece of information has an unambiguous home. When accessing
+ * the information, the shard with the longest matching data tree identifier is used,
+ * which is why this interface treats it is a prefix.
+ *
+ * Whenever a parent/child relationship is changed, the parent is notified, so it can
+ * understand that a logical child has been attached.
+ */
+public interface DOMDataTreeShardingService extends DOMService {
+    /**
+     * Register a shard as responsible for a particular subtree prefix.
+     *
+     * @param prefix Data tree identifier, may not be null.
+     * @param shard Responsible shard instance
+     * @return A registration. To remove the shard's binding, close the registration.
+     * @throws DOMDataTreeShardingConflictException if the prefix is already bound
+     */
+    @Nonnull <T extends DOMDataTreeShard> ListenerRegistration<T> registerDataTreeShard(@Nonnull DOMDataTreeIdentifier prefix, @Nonnull T shard) throws DOMDataTreeShardingConflictException;
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/test/java/org/opendaylight/controller/md/sal/dom/api/AbstractDOMDataTreeServiceTestSuite.java b/opendaylight/md-sal/sal-dom-api/src/test/java/org/opendaylight/controller/md/sal/dom/api/AbstractDOMDataTreeServiceTestSuite.java
new file mode 100644 (file)
index 0000000..896c606
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import static org.junit.Assert.assertNotNull;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.net.URI;
+import java.util.Collections;
+import javax.annotation.Nonnull;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+
+/**
+ * Abstract test suite demonstrating various access patterns on how a {@link DOMDataTreeService}
+ * can be used.
+ */
+public abstract class AbstractDOMDataTreeServiceTestSuite {
+    protected static final QNameModule TEST_MODULE = QNameModule.create(URI.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:store"), null);
+
+    protected static final YangInstanceIdentifier UNORDERED_CONTAINER_IID = YangInstanceIdentifier.create(
+        new NodeIdentifier(QName.create(TEST_MODULE, "lists")),
+        new NodeIdentifier(QName.create(TEST_MODULE, "unordered-container")));
+    protected static final DOMDataTreeIdentifier UNORDERED_CONTAINER_TREE = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, UNORDERED_CONTAINER_IID);
+
+    /**
+     * Return a reference to the service used in this test. The instance
+     * needs to be reused within the same test and must be isolated between
+     * tests.
+     *
+     * @return {@link DOMDataTreeService} instance.
+     */
+    protected abstract @Nonnull DOMDataTreeService service();
+
+    /**
+     * A simple unbound producer. It write some basic things into the data store based on the
+     * test model.
+     * @throws DOMDataTreeProducerException
+     * @throws TransactionCommitFailedException
+     */
+    @Test
+    public final void testBasicProducer() throws DOMDataTreeProducerException, TransactionCommitFailedException {
+        // Create a producer. It is an AutoCloseable resource, hence the try-with pattern
+        try (final DOMDataTreeProducer prod = service().createProducer(Collections.singleton(UNORDERED_CONTAINER_TREE))) {
+            assertNotNull(prod);
+
+            final DOMDataWriteTransaction tx = prod.createTransaction(true);
+            assertNotNull(tx);
+
+            tx.put(LogicalDatastoreType.OPERATIONAL, UNORDERED_CONTAINER_IID, ImmutableContainerNodeBuilder.create().build());
+
+            final CheckedFuture<Void, TransactionCommitFailedException> f = tx.submit();
+            assertNotNull(f);
+
+            f.checkedGet();
+        }
+    }
+
+    // TODO: simple listener
+}
index 08888c13cffec8b43da6efa8fb9703bcc9beb37c..8ee928e87835460097b712271ecf5744a4144276 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.md.sal.dom.broker.impl;
 
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
+import java.util.Collection;
 import java.util.EnumMap;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -77,7 +78,7 @@ abstract class AbstractDOMForwardedTransactionFactory<T extends DOMStoreTransact
      *         the Future fails with a {@link TransactionCommitFailedException}.
      */
     protected abstract CheckedFuture<Void,TransactionCommitFailedException> submit(final DOMDataWriteTransaction transaction,
-            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts);
+            final Collection<DOMStoreThreePhaseCommitCohort> cohorts);
 
     /**
      * Creates a new composite read-only transaction
index e0ac702dad59c8d0119460e13b9a87a9535a8cc1..b85350f95d25afde4b346842c3b457f8a23626c0 100644 (file)
@@ -8,9 +8,9 @@ package org.opendaylight.controller.md.sal.dom.broker.impl;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
-import com.google.common.collect.Iterables;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collection;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
@@ -32,18 +32,16 @@ final class CommitCoordinationTask implements Callable<Void> {
     };
 
     private static final Logger LOG = LoggerFactory.getLogger(CommitCoordinationTask.class);
-    private final Iterable<DOMStoreThreePhaseCommitCohort> cohorts;
+    private final Collection<DOMStoreThreePhaseCommitCohort> cohorts;
     private final DurationStatisticsTracker commitStatTracker;
     private final DOMDataWriteTransaction tx;
-    private final int cohortSize;
 
     public CommitCoordinationTask(final DOMDataWriteTransaction transaction,
-            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts,
+            final Collection<DOMStoreThreePhaseCommitCohort> cohorts,
             final DurationStatisticsTracker commitStatTracker) {
         this.tx = Preconditions.checkNotNull(transaction, "transaction must not be null");
         this.cohorts = Preconditions.checkNotNull(cohorts, "cohorts must not be null");
         this.commitStatTracker = commitStatTracker;
-        this.cohortSize = Iterables.size(cohorts);
     }
 
     @Override
@@ -115,7 +113,7 @@ final class CommitCoordinationTask implements Callable<Void> {
      *
      */
     private ListenableFuture<?>[] canCommitAll() {
-        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohortSize];
+        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohorts.size()];
         int i = 0;
         for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
             ops[i++] = cohort.canCommit();
@@ -162,7 +160,7 @@ final class CommitCoordinationTask implements Callable<Void> {
      *
      */
     private ListenableFuture<?>[] preCommitAll() {
-        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohortSize];
+        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohorts.size()];
         int i = 0;
         for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
             ops[i++] = cohort.preCommit();
@@ -205,7 +203,7 @@ final class CommitCoordinationTask implements Callable<Void> {
      * @return List of all cohorts futures from can commit phase.
      */
     private ListenableFuture<?>[] commitAll() {
-        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohortSize];
+        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohorts.size()];
         int i = 0;
         for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
             ops[i++] = cohort.commit();
@@ -256,7 +254,7 @@ final class CommitCoordinationTask implements Callable<Void> {
      */
     private ListenableFuture<Void> abortAsyncAll() {
 
-        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohortSize];
+        final ListenableFuture<?>[] ops = new ListenableFuture<?>[cohorts.size()];
         int i = 0;
         for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
             ops[i++] = cohort.abort();
index 77387c761cd6b26efea4c05471eb9632c695c578..201eb81a94155b49a0b32d00807b53c6ebebdb11 100644 (file)
@@ -10,6 +10,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
+import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 import java.util.concurrent.atomic.AtomicLong;
@@ -87,7 +88,7 @@ final class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTransa
 
     @Override
     public CheckedFuture<Void, TransactionCommitFailedException> submit(
-            final DOMDataWriteTransaction transaction, final Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
+            final DOMDataWriteTransaction transaction, final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
         checkNotFailed();
         checkNotClosed();
 
index 268b1b85840fcecbc4b0de55fc6e8c903d5243e2..ad23e3a72bc9242878e3b13faba6727ed474fa65 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
+import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.RejectedExecutionException;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -57,7 +58,7 @@ public class SerializedDOMDataBroker extends AbstractDOMDataBroker {
 
     @Override
     protected CheckedFuture<Void,TransactionCommitFailedException> submit(final DOMDataWriteTransaction transaction,
-            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
+            final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
         Preconditions.checkArgument(transaction != null, "Transaction must not be null.");
         Preconditions.checkArgument(cohorts != null, "Cohorts must not be null.");
         LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier());
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardRegistration.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardRegistration.java
new file mode 100644 (file)
index 0000000..9a71089
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShard;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+
+final class ShardRegistration<T extends DOMDataTreeShard> extends AbstractListenerRegistration<T> {
+    private final DOMDataTreeIdentifier prefix;
+    private final ShardedDOMDataTree tree;
+
+    protected ShardRegistration(final ShardedDOMDataTree tree, final DOMDataTreeIdentifier prefix, final T shard) {
+        super(shard);
+        this.tree = Preconditions.checkNotNull(tree);
+        this.prefix = Preconditions.checkNotNull(prefix);
+    }
+
+    DOMDataTreeIdentifier getPrefix() {
+        return prefix;
+    }
+
+    @Override
+    protected void removeRegistration() {
+        tree.removeShard(this);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataTree.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataTree.java
new file mode 100644 (file)
index 0000000..11eae5d
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeProducer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShard;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShardingConflictException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShardingService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ShardedDOMDataTree implements DOMDataTreeService, DOMDataTreeShardingService {
+    private static final Logger LOG = LoggerFactory.getLogger(ShardedDOMDataTree.class);
+    private final Map<LogicalDatastoreType, ShardingTableEntry> shardingTables = new EnumMap<>(LogicalDatastoreType.class);
+    @GuardedBy("this")
+    private final Map<DOMDataTreeIdentifier, DOMDataTreeProducer> idToProducer = new TreeMap<>();
+
+    @GuardedBy("this")
+    private ShardingTableEntry lookupShard(final DOMDataTreeIdentifier prefix) {
+        final ShardingTableEntry t = shardingTables.get(prefix.getDatastoreType());
+        if (t == null) {
+            return null;
+        }
+
+        return t.lookup(prefix.getRootIdentifier());
+    }
+
+    @GuardedBy("this")
+    private void storeShard(final DOMDataTreeIdentifier prefix, final ShardRegistration<?> reg) {
+        ShardingTableEntry t = shardingTables.get(prefix.getDatastoreType());
+        if (t == null) {
+            t = new ShardingTableEntry();
+            shardingTables.put(prefix.getDatastoreType(), t);
+        }
+
+        t.store(prefix.getRootIdentifier(), reg);
+    }
+
+    void removeShard(final ShardRegistration<?> reg) {
+        final DOMDataTreeIdentifier prefix = reg.getPrefix();
+        final ShardRegistration<?> parentReg;
+
+        synchronized (this) {
+            final ShardingTableEntry t = shardingTables.get(prefix.getDatastoreType());
+            if (t == null) {
+                LOG.warn("Shard registration {} points to non-existent table", reg);
+                return;
+            }
+
+            t.remove(prefix.getRootIdentifier());
+            parentReg = lookupShard(prefix).getRegistration();
+
+            /*
+             * FIXME: adjust all producers. This is tricky, as we need different locking strategy,
+             *        simply because we risk AB/BA deadlock with a producer being split off from
+             *        a producer.
+             *
+             */
+        }
+
+        if (parentReg != null) {
+            parentReg.getInstance().onChildDetached(prefix, reg.getInstance());
+        }
+    }
+
+    @Override
+    public <T extends DOMDataTreeShard> ListenerRegistration<T> registerDataTreeShard(final DOMDataTreeIdentifier prefix, final T shard) throws DOMDataTreeShardingConflictException {
+        final ShardRegistration<T> reg;
+        final ShardRegistration<?> parentReg;
+
+        synchronized (this) {
+            /*
+             * Lookup the parent shard (e.g. the one which currently matches the prefix),
+             * and if it exists, check if its registration prefix does not collide with
+             * this registration.
+             */
+            final ShardingTableEntry parent = lookupShard(prefix);
+            parentReg = parent.getRegistration();
+            if (parentReg != null && prefix.equals(parentReg.getPrefix())) {
+                throw new DOMDataTreeShardingConflictException(String.format("Prefix %s is already occupied by shard {}", prefix, parentReg.getInstance()));
+            }
+
+            // FIXME: wrap the shard in a proper adaptor based on implemented interface
+
+            reg = new ShardRegistration<T>(this, prefix, shard);
+
+            storeShard(prefix, reg);
+
+            // FIXME: update any producers/registrations
+        }
+
+        // Notify the parent shard
+        if (parentReg != null) {
+            parentReg.getInstance().onChildAttached(prefix, shard);
+        }
+
+        return reg;
+    }
+
+    @GuardedBy("this")
+    private DOMDataTreeProducer findProducer(final DOMDataTreeIdentifier subtree) {
+        for (Entry<DOMDataTreeIdentifier, DOMDataTreeProducer> e : idToProducer.entrySet()) {
+            if (e.getKey().contains(subtree)) {
+                return e.getValue();
+            }
+        }
+
+        return null;
+    }
+
+    synchronized void destroyProducer(final ShardedDOMDataTreeProducer producer) {
+        for (DOMDataTreeIdentifier s : producer.getSubtrees()) {
+            DOMDataTreeProducer r = idToProducer.remove(s);
+            if (!producer.equals(r)) {
+                LOG.error("Removed producer %s on subtree %s while removing %s", r, s, producer);
+            }
+        }
+    }
+
+    @GuardedBy("this")
+    private DOMDataTreeProducer createProducer(final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap) {
+        // Record the producer's attachment points
+        final DOMDataTreeProducer ret = ShardedDOMDataTreeProducer.create(this, shardMap);
+        for (DOMDataTreeIdentifier s : shardMap.keySet()) {
+            idToProducer.put(s, ret);
+        }
+
+        return ret;
+    }
+
+    @Override
+    public synchronized DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
+        Preconditions.checkArgument(!subtrees.isEmpty(), "Subtrees may not be empty");
+
+        final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap = new HashMap<>();
+        for (DOMDataTreeIdentifier s : subtrees) {
+            // Attempting to create a disconnected producer -- all subtrees have to be unclaimed
+            final DOMDataTreeProducer producer = findProducer(s);
+            Preconditions.checkArgument(producer == null, "Subtree %s is attached to producer %s", s, producer);
+
+            shardMap.put(s, lookupShard(s).getRegistration().getInstance());
+        }
+
+        return createProducer(shardMap);
+    }
+
+    synchronized DOMDataTreeProducer createProducer(final ShardedDOMDataTreeProducer parent, final Collection<DOMDataTreeIdentifier> subtrees) {
+        Preconditions.checkNotNull(parent);
+
+        final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap = new HashMap<>();
+        for (DOMDataTreeIdentifier s : subtrees) {
+            shardMap.put(s, lookupShard(s).getRegistration().getInstance());
+        }
+
+        return createProducer(shardMap);
+    }
+
+    @Override
+    public synchronized <T extends DOMDataTreeListener> ListenerRegistration<T> registerListener(final T listener, final Collection<DOMDataTreeIdentifier> subtrees, final boolean allowRxMerges, final Collection<DOMDataTreeProducer> producers) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataTreeProducer.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataTreeProducer.java
new file mode 100644 (file)
index 0000000..9712b25
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableBiMap.Builder;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeProducer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeProducerBusyException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeProducerException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeShard;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class ShardedDOMDataTreeProducer implements DOMDataTreeProducer {
+    private static final Logger LOG = LoggerFactory.getLogger(ShardedDOMDataTreeProducer.class);
+    private final BiMap<DOMDataTreeShard, DOMStoreTransactionChain> shardToChain;
+    private final Map<DOMDataTreeIdentifier, DOMDataTreeShard> idToShard;
+    private final ShardedDOMDataTree dataTree;
+
+    @GuardedBy("this")
+    private Map<DOMDataTreeIdentifier, DOMDataTreeProducer> children = Collections.emptyMap();
+    @GuardedBy("this")
+    private DOMDataWriteTransaction openTx;
+    @GuardedBy("this")
+    private boolean closed;
+
+    ShardedDOMDataTreeProducer(final ShardedDOMDataTree dataTree, final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap, final Set<DOMDataTreeShard> shards) {
+        this.dataTree = Preconditions.checkNotNull(dataTree);
+
+        // Create shard -> chain map
+        final Builder<DOMDataTreeShard, DOMStoreTransactionChain> cb = ImmutableBiMap.builder();
+        final Queue<Exception> es = new LinkedList<>();
+
+        for (DOMDataTreeShard s : shards) {
+            if (s instanceof DOMStore) {
+                try {
+                    final DOMStoreTransactionChain c = ((DOMStore)s).createTransactionChain();
+                    LOG.trace("Using DOMStore chain {} to access shard {}", c, s);
+                    cb.put(s, c);
+                } catch (Exception e) {
+                    LOG.error("Failed to instantiate chain for shard {}", s, e);
+                    es.add(e);
+                }
+            } else {
+                LOG.error("Unhandled shard instance type {}", s.getClass());
+            }
+        }
+        this.shardToChain = cb.build();
+
+        // An error was encountered, close chains and report the error
+        if (shardToChain.size() != shards.size()) {
+            for (DOMStoreTransactionChain c : shardToChain.values()) {
+                try {
+                    c.close();
+                } catch (Exception e) {
+                    LOG.warn("Exception raised while closing chain %s", c, e);
+                }
+            }
+
+            final IllegalStateException e = new IllegalStateException("Failed to completely allocate contexts", es.poll());
+            while (!es.isEmpty()) {
+                e.addSuppressed(es.poll());
+            }
+
+            throw e;
+        }
+
+        idToShard = ImmutableMap.copyOf(shardMap);
+    }
+
+    @Override
+    public synchronized DOMDataWriteTransaction createTransaction(final boolean isolated) {
+        Preconditions.checkState(!closed, "Producer is already closed");
+        Preconditions.checkState(openTx == null, "Transaction %s is still open", openTx);
+
+        // Allocate backing transactions
+        final Map<DOMDataTreeShard, DOMStoreWriteTransaction> shardToTx = new HashMap<>();
+        for (Entry<DOMDataTreeShard, DOMStoreTransactionChain> e : shardToChain.entrySet()) {
+            shardToTx.put(e.getKey(), e.getValue().newWriteOnlyTransaction());
+        }
+
+        // Create the ID->transaction map
+        final ImmutableMap.Builder<DOMDataTreeIdentifier, DOMStoreWriteTransaction> b = ImmutableMap.builder();
+        for (Entry<DOMDataTreeIdentifier, DOMDataTreeShard> e : idToShard.entrySet()) {
+            b.put(e.getKey(), shardToTx.get(e.getValue()));
+        }
+
+        final ShardedDOMDataWriteTransaction ret = new ShardedDOMDataWriteTransaction(this, b.build());
+        openTx = ret;
+        return ret;
+    }
+
+    @GuardedBy("this")
+    private boolean haveSubtree(final DOMDataTreeIdentifier subtree) {
+        for (DOMDataTreeIdentifier i : idToShard.keySet()) {
+            if (i.contains(subtree)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @GuardedBy("this")
+    private DOMDataTreeProducer lookupChild(final DOMDataTreeIdentifier s) {
+        for (Entry<DOMDataTreeIdentifier, DOMDataTreeProducer> e : children.entrySet()) {
+            if (e.getKey().contains(s)) {
+                return e.getValue();
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public synchronized DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
+        Preconditions.checkState(!closed, "Producer is already closed");
+        Preconditions.checkState(openTx == null, "Transaction %s is still open", openTx);
+
+        for (DOMDataTreeIdentifier s : subtrees) {
+            // Check if the subtree was visible at any time
+            if (!haveSubtree(s)) {
+                throw new IllegalArgumentException(String.format("Subtree %s was never available in producer %s", s, this));
+            }
+
+            // Check if the subtree has not been delegated to a child
+            final DOMDataTreeProducer child = lookupChild(s);
+            Preconditions.checkArgument(child == null, "Subtree %s is delegated to child producer %s", s, child);
+
+            // Check if part of the requested subtree is not delegated to a child.
+            for (DOMDataTreeIdentifier c : children.keySet()) {
+                if (s.contains(c)) {
+                    throw new IllegalArgumentException(String.format("Subtree %s cannot be delegated as it is superset of already-delegated %s", s, c));
+                }
+            }
+        }
+
+        final DOMDataTreeProducer ret = dataTree.createProducer(this, subtrees);
+        final ImmutableMap.Builder<DOMDataTreeIdentifier, DOMDataTreeProducer> cb = ImmutableMap.builder();
+        cb.putAll(children);
+        for (DOMDataTreeIdentifier s : subtrees) {
+            cb.put(s, ret);
+        }
+
+        children = cb.build();
+        return ret;
+    }
+
+    @Override
+    public synchronized void close() throws DOMDataTreeProducerException {
+        if (!closed) {
+            if (openTx != null) {
+                throw new DOMDataTreeProducerBusyException(String.format("Transaction %s is still open", openTx));
+            }
+
+            closed = true;
+            dataTree.destroyProducer(this);
+        }
+    }
+
+    static DOMDataTreeProducer create(final ShardedDOMDataTree dataTree, final Map<DOMDataTreeIdentifier, DOMDataTreeShard> shardMap) {
+        /*
+         * FIXME: we do not allow multiple multiple shards in a producer because we do not implement the
+         *        synchronization primitives yet
+         */
+        final Set<DOMDataTreeShard> shards = ImmutableSet.copyOf(shardMap.values());
+        if (shards.size() > 1) {
+            throw new UnsupportedOperationException("Cross-shard producers are not supported yet");
+        }
+
+        return new ShardedDOMDataTreeProducer(dataTree, shardMap, shards);
+    }
+
+    Set<DOMDataTreeIdentifier> getSubtrees() {
+        return idToShard.keySet();
+    }
+
+    synchronized void cancelTransaction(final ShardedDOMDataWriteTransaction transaction) {
+        if (!openTx.equals(transaction)) {
+            LOG.warn("Transaction {} is not open in producer {}", transaction, this);
+            return;
+        }
+
+        LOG.debug("Transaction {} cancelled", transaction);
+        openTx = null;
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardedDOMDataWriteTransaction.java
new file mode 100644 (file)
index 0000000..33f15e3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@NotThreadSafe
+final class ShardedDOMDataWriteTransaction implements DOMDataWriteTransaction {
+    private static final Logger LOG = LoggerFactory.getLogger(ShardedDOMDataWriteTransaction.class);
+    private static final AtomicLong COUNTER = new AtomicLong();
+    private final Map<DOMDataTreeIdentifier, DOMStoreWriteTransaction> idToTransaction;
+    private final ShardedDOMDataTreeProducer producer;
+    private final String identifier;
+    @GuardedBy("this")
+    private boolean closed =  false;
+
+    ShardedDOMDataWriteTransaction(final ShardedDOMDataTreeProducer producer, final Map<DOMDataTreeIdentifier, DOMStoreWriteTransaction> idToTransaction) {
+        this.producer = Preconditions.checkNotNull(producer);
+        this.idToTransaction = Preconditions.checkNotNull(idToTransaction);
+        this.identifier = "SHARDED-DOM-" + COUNTER.getAndIncrement();
+    }
+
+    // FIXME: use atomic operations
+    @GuardedBy("this")
+    private DOMStoreWriteTransaction lookup(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+        final DOMDataTreeIdentifier id = new DOMDataTreeIdentifier(store, path);
+
+        for (Entry<DOMDataTreeIdentifier, DOMStoreWriteTransaction> e : idToTransaction.entrySet()) {
+            if (e.getKey().contains(id)) {
+                return e.getValue();
+            }
+        }
+
+        throw new IllegalArgumentException(String.format("Path %s is not acessible from transaction %s", id, this));
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public synchronized boolean cancel() {
+        if (closed) {
+            return false;
+        }
+
+        LOG.debug("Cancelling transaction {}", identifier);
+        for (DOMStoreWriteTransaction tx : ImmutableSet.copyOf(idToTransaction.values())) {
+            tx.close();
+        }
+
+        closed = true;
+        producer.cancelTransaction(this);
+        return true;
+    }
+
+    @Override
+    public synchronized CheckedFuture<Void, TransactionCommitFailedException> submit() {
+        Preconditions.checkState(!closed, "Transaction %s is already closed", identifier);
+
+        final Set<DOMStoreWriteTransaction> txns = ImmutableSet.copyOf(idToTransaction.values());
+        final List<DOMStoreThreePhaseCommitCohort> cohorts = new ArrayList<>(txns.size());
+        for (DOMStoreWriteTransaction tx : txns) {
+            cohorts.add(tx.ready());
+        }
+
+        try {
+            return Futures.immediateCheckedFuture(new CommitCoordinationTask(this, cohorts, null).call());
+        } catch (TransactionCommitFailedException e) {
+            return Futures.immediateFailedCheckedFuture(e);
+        }
+    }
+
+    @Override
+    @Deprecated
+    public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+        return AbstractDataTransaction.convertToLegacyCommitFuture(submit());
+    }
+
+    @Override
+    public synchronized void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+        lookup(store, path).delete(path);
+    }
+
+    @Override
+    public synchronized void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        lookup(store, path).write(path, data);
+    }
+
+    @Override
+    public synchronized void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        lookup(store, path).merge(path, data);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardingTableEntry.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/ShardingTableEntry.java
new file mode 100644 (file)
index 0000000..fcd0ebd
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import com.google.common.base.Preconditions;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class ShardingTableEntry implements Identifiable<PathArgument> {
+    private static final Logger LOG = LoggerFactory.getLogger(ShardingTableEntry.class);
+    private final Map<PathArgument, ShardingTableEntry> children = Collections.emptyMap();
+    private final PathArgument identifier;
+    private ShardRegistration<?> registration;
+
+    ShardingTableEntry() {
+        identifier = null;
+    }
+
+    ShardingTableEntry(final PathArgument identifier) {
+        this.identifier = Preconditions.checkNotNull(identifier);
+    }
+
+    @Override
+    public PathArgument getIdentifier() {
+        return identifier;
+    }
+
+    public ShardRegistration<?> getRegistration() {
+        return registration;
+    }
+
+    ShardingTableEntry lookup(final YangInstanceIdentifier id) {
+        final Iterator<PathArgument> it = id.getPathArguments().iterator();
+        ShardingTableEntry entry = this;
+
+        while (it.hasNext()) {
+            final PathArgument a = it.next();
+            final ShardingTableEntry child = entry.children.get(a);
+            if (child == null) {
+                LOG.debug("Lookup of {} stopped at {}", id, a);
+                break;
+            }
+
+            entry = child;
+        }
+
+        return entry;
+    }
+
+    void store(final YangInstanceIdentifier id, final ShardRegistration<?> reg) {
+        final Iterator<PathArgument> it = id.getPathArguments().iterator();
+        ShardingTableEntry entry = this;
+
+        while (it.hasNext()) {
+            final PathArgument a = it.next();
+            ShardingTableEntry child = entry.children.get(a);
+            if (child == null) {
+                child = new ShardingTableEntry(a);
+                entry.children.put(a, child);
+            }
+        }
+
+        Preconditions.checkState(entry.registration == null);
+        entry.registration = reg;
+    }
+
+    private boolean remove(final Iterator<PathArgument> it) {
+        if (it.hasNext()) {
+            final PathArgument arg = it.next();
+            final ShardingTableEntry child = children.get(arg);
+            if (child != null) {
+                if (child.remove(it)) {
+                    children.remove(arg);
+                }
+            } else {
+                LOG.warn("Cannot remove non-existent child {}", arg);
+            }
+        }
+
+        return registration == null && children.isEmpty();
+    }
+
+    void remove(final YangInstanceIdentifier id) {
+        this.remove(id.getPathArguments().iterator());
+    }
+}
index 2f02f981ab198fe248a33a33ac90187b57064211..2a7c8b6682cbdaf0a9f0a8ff7cd194a9f22c5c12 100644 (file)
@@ -60,8 +60,8 @@ public class DOMBrokerPerformanceTest {
 
     @Before
     public void setupStore() {
-        InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER", MoreExecutors.sameThreadExecutor());
-        InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG", MoreExecutors.sameThreadExecutor());
+        InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER", MoreExecutors.newDirectExecutorService());
+        InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG", MoreExecutors.newDirectExecutorService());
         schemaContext = TestModel.createTestContext();
 
         operStore.onGlobalContextUpdated(schemaContext);
index c1d301c549b8cd1964f9b296cf9e13a3a2d29774..cd8ac0998052f73c94a558443b3663583e82125b 100644 (file)
@@ -57,9 +57,9 @@ public class DOMBrokerTest {
     public void setupStore() {
 
         InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
-                MoreExecutors.sameThreadExecutor());
+                MoreExecutors.newDirectExecutorService());
         InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
-                MoreExecutors.sameThreadExecutor());
+                MoreExecutors.newDirectExecutorService());
         schemaContext = TestModel.createTestContext();
 
         operStore.onGlobalContextUpdated(schemaContext);
index 03d39a2a62a33cf5b61f468401a338b77133d622..aba78f755912275c1cf001e8225fe02ac7b9b0f6 100644 (file)
@@ -41,8 +41,8 @@ public class DOMTransactionChainTest {
 
     @Before
     public void setupStore() {
-        InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER", MoreExecutors.sameThreadExecutor());
-        InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG", MoreExecutors.sameThreadExecutor());
+        InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER", MoreExecutors.newDirectExecutorService());
+        InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG", MoreExecutors.newDirectExecutorService());
         schemaContext = TestModel.createTestContext();
 
         operStore.onGlobalContextUpdated(schemaContext);
index c7fd20248de7e14a5dfb70fcc4e671d959de4b91..f0e27cf2ac928642a40b0eb37a9d250d77bef4b5 100644 (file)
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
index c7ee3a5c0c8a2346dabae2c4045a67839a4ab312..85ae59b161f6646d964d790a5a6fc2c38560c873 100644 (file)
@@ -81,7 +81,6 @@
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
-      <version>${slf4j.version}</version>
       <scope>test</scope>
     </dependency>
 
@@ -94,7 +93,6 @@
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
-      <version>1.7.7</version>
     </dependency>
 
   </dependencies>
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-shade-plugin</artifactId>
-            <version>1.5</version>
             <executions>
                 <execution>
                     <phase>package</phase>
index 3dffdfce575d82a0118c11d137fe501a450defe7..0b72a32f1033884ba983c71b2651a4a88ad6c7b1 100644 (file)
@@ -11,6 +11,8 @@ package org.opendaylight.controller.dummy.datastore;
 import akka.actor.Props;
 import akka.actor.UntypedActor;
 import akka.japi.Creator;
+import com.google.common.base.Stopwatch;
+import java.util.concurrent.TimeUnit;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
@@ -27,6 +29,7 @@ public class DummyShard extends UntypedActor{
     private final Logger LOG = LoggerFactory.getLogger(DummyShard.class);
     private long lastMessageIndex  = -1;
     private long lastMessageSize = 0;
+    private Stopwatch appendEntriesWatch;
 
     public DummyShard(Configuration configuration, String followerId) {
         this.configuration = configuration;
@@ -57,10 +60,21 @@ public class DummyShard extends UntypedActor{
     }
 
     protected void handleAppendEntries(AppendEntries req) throws InterruptedException {
-
         LOG.info("{} - Received AppendEntries message : leader term = {}, index = {}, prevLogIndex = {}, size = {}",
                 followerId, req.getTerm(),req.getLeaderCommit(), req.getPrevLogIndex(), req.getEntries().size());
 
+        if(appendEntriesWatch != null){
+            long elapsed = appendEntriesWatch.elapsed(TimeUnit.SECONDS);
+            if(elapsed >= 5){
+                LOG.error("More than 5 seconds since last append entry, elapsed Time = {} seconds" +
+                                ", leaderCommit = {}, prevLogIndex = {}, size = {}",
+                        elapsed, req.getLeaderCommit(), req.getPrevLogIndex(), req.getEntries().size());
+            }
+            appendEntriesWatch.reset().start();
+        } else {
+            appendEntriesWatch = Stopwatch.createStarted();
+        }
+
         if(lastMessageIndex == req.getLeaderCommit() && req.getEntries().size() > 0 && lastMessageSize > 0){
             LOG.error("{} - Duplicate message with leaderCommit = {} prevLogIndex = {} received", followerId, req.getLeaderCommit(), req.getPrevLogIndex());
         }
index 067c048231d1da73c7c550fc4934b9523132c396..cd2d082079981b4f5323f823471fb3a7299c163c 100644 (file)
@@ -3,4 +3,4 @@ org.slf4j.simpleLogger.dateTimeFormat=hh:mm:ss,S a
 org.slf4j.simpleLogger.logFile=System.out
 org.slf4j.simpleLogger.showShortLogName=true
 org.slf4j.simpleLogger.levelInBrackets=true
-org.slf4j.simpleLogger.defaultLogLevel=info
\ No newline at end of file
+org.slf4j.simpleLogger.defaultLogLevel=error
\ No newline at end of file
index 4720f4b4b9f4fcc0c04cad1b2470f2fb15097006..9de4892d9140b1afc7ea3a93ef532ca1bf97edeb 100644 (file)
@@ -45,7 +45,7 @@ public class InMemoryDataStoreTest {
 
     @Before
     public void setupStore() {
-        domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.sameThreadExecutor());
+        domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
         schemaContext = TestModel.createTestContext();
         domStore.onGlobalContextUpdated(schemaContext);
     }
index 15e5f716f62c17ccb66d29f09430d8aa4dac7f5b..e7af4dffae98b0b0543a8919c8ead80c6132512a 100644 (file)
@@ -31,7 +31,7 @@ public class SchemaUpdateForTransactionTest {
 
     @Before
     public void setupStore() {
-        domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.sameThreadExecutor());
+        domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.newDirectExecutorService());
         loadSchemas(RockTheHouseInput.class);
     }
 
index f6e6461bf54707d48fc767d411e321c0672733af..a01933c295bea088f5f86e7f0ad417f4d4e2be58 100644 (file)
@@ -8,10 +8,9 @@
 
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
-import java.util.concurrent.ExecutorService;
-
 import com.google.common.util.concurrent.ForwardingExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
+import java.util.concurrent.ExecutorService;
 
 /**
  * A forwarding Executor used by unit tests for DataChangeListener notifications
@@ -21,13 +20,13 @@ import com.google.common.util.concurrent.MoreExecutors;
 public class TestDCLExecutorService extends ForwardingExecutorService {
 
     // Start with a same thread executor to avoid timing issues during test setup.
-    private volatile ExecutorService currentExecutor = MoreExecutors.sameThreadExecutor();
+    private volatile ExecutorService currentExecutor = MoreExecutors.newDirectExecutorService();
 
     // The real executor to use when test setup is complete.
     private final ExecutorService postSetupExecutor;
 
 
-    public TestDCLExecutorService( ExecutorService postSetupExecutor ) {
+    public TestDCLExecutorService( final ExecutorService postSetupExecutor ) {
         this.postSetupExecutor = postSetupExecutor;
     }
 
index b966fae3d4e458f55796fbc0e6e26213b093bd83..44b2435da2284358b4a2ed13cbb6e699e23f2115 100644 (file)
@@ -111,7 +111,7 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
                 new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaContextFactory, new NetconfStateSchemas.NetconfStateSchemasResolverImpl());
 
         final NetconfDevice device =
-                new NetconfDevice(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, new NetconfMessageTransformer(), true);
+                new NetconfDevice(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, new NetconfMessageTransformer(), getReconnectOnChangedSchema());
 
         final NetconfDeviceCommunicator listener = userCapabilities.isPresent() ?
                 new NetconfDeviceCommunicator(id, device, userCapabilities.get()) : new NetconfDeviceCommunicator(id, device);
index 9a5b239024c5bb0cbca3798de58ccc102a994224..281f82ba2aa04d9085d9127e4aeb7ad10cb8d400 100644 (file)
@@ -223,6 +223,8 @@ public final class NetconfDevice implements RemoteDevice<NetconfSessionPreferenc
 
     @Override
     public void onRemoteSessionDown() {
+        notificationHandler.onRemoteSchemaDown();
+
         salFacade.onDeviceDisconnected();
         for (final SchemaSourceRegistration<? extends SchemaSourceRepresentation> sourceRegistration : sourceRegistrations) {
             sourceRegistration.close();
@@ -314,6 +316,7 @@ public final class NetconfDevice implements RemoteDevice<NetconfSessionPreferenc
                 logger.warn("{}: Netconf device provides additional yang models not reported in hello message capabilities: {}",
                         id, providedSourcesNotRequired);
                 logger.warn("{}: Adding provided but not required sources as required to prevent failures", id);
+                logger.debug("{}: Netconf device reported in hello: {}", id, requiredSources);
                 requiredSources.addAll(providedSourcesNotRequired);
             }
 
index b5927f0bd540519ca60aadd4b095df3e81acbc89..bc3326e1ae5b58dc23dc7c14927a83d5d34d1fcf 100644 (file)
@@ -42,7 +42,7 @@ final class NotificationHandler {
 
     synchronized void handleNotification(final NetconfMessage notification) {
         if(passNotifications) {
-            passNotification(messageTransformer.toNotification(notification));
+            passNotification(transformNotification(notification));
         } else {
             queueNotification(notification);
         }
@@ -55,12 +55,18 @@ final class NotificationHandler {
         passNotifications = true;
 
         for (final NetconfMessage cachedNotification : queue) {
-            passNotification(messageTransformer.toNotification(cachedNotification));
+            passNotification(transformNotification(cachedNotification));
         }
 
         queue.clear();
     }
 
+    private CompositeNode transformNotification(final NetconfMessage cachedNotification) {
+        final CompositeNode parsedNotification = messageTransformer.toNotification(cachedNotification);
+        Preconditions.checkNotNull(parsedNotification, "%s: Unable to parse received notification: %s", id, cachedNotification);
+        return parsedNotification;
+    }
+
     private void queueNotification(final NetconfMessage notification) {
         Preconditions.checkState(passNotifications == false);
 
@@ -74,7 +80,6 @@ final class NotificationHandler {
 
     private synchronized void passNotification(final CompositeNode parsedNotification) {
         logger.debug("{}: Forwarding notification {}", id, parsedNotification);
-        Preconditions.checkNotNull(parsedNotification);
 
         if(filter == null || filter.filterNotification(parsedNotification).isPresent()) {
             salFacade.onNotification(parsedNotification);
@@ -85,6 +90,11 @@ final class NotificationHandler {
         this.filter = filter;
     }
 
+    synchronized void onRemoteSchemaDown() {
+        queue.clear();
+        passNotifications = false;
+    }
+
     static interface NotificationFilter {
 
         Optional<CompositeNode> filterNotification(CompositeNode notification);
diff --git a/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-of-migration-test-model.yang b/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-of-migration-test-model.yang
new file mode 100644 (file)
index 0000000..24ff5dd
--- /dev/null
@@ -0,0 +1,156 @@
+module opendaylight-of-migration-test-model {
+
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:of-migration-test-model";
+    prefix of-migration-test;
+
+    import opendaylight-mdsal-list-test {prefix test;}
+    import yang-ext {prefix ext;}
+    import opendaylight-mdsal-augment-test {prefix aug;}
+    import opendaylight-test-routed-rpc {prefix routed;}
+
+    description
+        "This module contains a collection of YANG definitions used for
+        test cases that used to depend on flow model.";
+
+    revision 2015-02-10 {
+    }
+
+    typedef bit-flags {
+        type bits {
+            bit FLAG_ONE;
+            bit FLAG_TWO;
+            bit FLAG_THREE;
+            bit FLAG_FOUR;
+            bit FLAG_FIVE;
+        }
+    }
+
+    typedef custom-enum {
+        type enumeration {
+            enum type1;
+            enum type2;
+            enum type3;
+        }
+    }
+
+    grouping enum-grouping {
+        leaf attr-enum {
+            type custom-enum;
+        }
+    }
+
+    grouping aug-grouping {
+        container cont1 {
+            leaf attr-str {
+                type string;
+            }
+        }
+
+        container cont2 {
+            list contlist1 {
+                key "attr-str";
+
+                leaf attr-str {
+                    type string;
+                }
+
+                uses enum-grouping;
+            }
+        }
+
+        leaf attr-str1 {
+            type string;
+        }
+
+        leaf attr-str2 {
+            type string;
+        }
+
+        leaf attr-str3 {
+            type string;
+        }
+
+        leaf attr-str4 {
+            type string;
+        }
+
+        list list1 {
+            key "attr-str";
+            leaf attr-str {
+                type string;
+            }
+
+            list list1-1 {
+                key "attr-int";
+                leaf attr-int {
+                    type int32;
+                }
+
+                leaf attr-str {
+                    type string;
+                }
+
+                leaf flags {
+                    type bit-flags;
+                }
+            }
+
+            list list1-2 {
+                key "attr-int";
+                leaf attr-int {
+                    type int32;
+                }
+
+                leaf attr-str {
+                    type string;
+                }
+            }
+        }
+    }
+
+    augment "/test:top/test:top-level-list" {
+        ext:augment-identifier tll-complex-augment;
+        uses aug-grouping;
+    }
+
+    augment "/test:top/test:top-level-list/list1/list1-1"  {
+        ext:augment-identifier list11-simple-augment;
+
+        leaf attr-str2 {
+            type string;
+        }
+
+        container cont {
+            leaf attr-int {
+                type int32;
+            }
+        }
+    }
+
+    augment "/test:top/test:top-level-list/test:nested-list/"  {
+        ext:augment-identifier nested-list-simple-augment;
+
+        leaf type {
+            type string;
+        }
+    }
+
+    rpc knock-knock {
+        input {
+            leaf knocker-id {
+                ext:context-reference routed:test-context;
+                type instance-identifier;
+            }
+
+            leaf question {
+                type string;
+            }
+        }
+
+        output {
+            leaf answer {
+                type string;
+            }
+        }
+    }
+}
index 4ae4de18f30f80580f237951e1cb1568180b5bb3..ba7b2f20e44058d7b9af4663003d36e4654400ea 100644 (file)
@@ -17,7 +17,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import javax.management.ObjectName;
 import javax.management.openmbean.OpenType;
-import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.BeanReader;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -46,9 +46,9 @@ public final class InstanceConfig {
     private final Map<String, AttributeIfc> yangToAttrConfig;
     private final String nullableDummyContainerName;
     private final Map<String, AttributeIfc> jmxToAttrConfig;
-    private final ConfigRegistryClient configRegistryClient;
+    private final BeanReader configRegistryClient;
 
-    public InstanceConfig(ConfigRegistryClient configRegistryClient, Map<String, AttributeIfc> yangNamesToAttributes,
+    public InstanceConfig(BeanReader configRegistryClient, Map<String, AttributeIfc> yangNamesToAttributes,
                           String nullableDummyContainerName) {
 
         this.yangToAttrConfig = yangNamesToAttributes;
index d736595719e8ac59247b65db130c5e490142e6ae..9c55953bbc853b01403eedb11eca38c828076762 100644 (file)
@@ -26,7 +26,7 @@ public enum Datastore {
             TransactionProvider transactionProvider) {
         switch (source) {
         case running:
-            return new RunningDatastoreQueryStrategy();
+            return new RunningDatastoreQueryStrategy(transactionProvider);
         case candidate:
             return new CandidateDatastoreQueryStrategy(transactionProvider);
         default:
index ca6a8c46b95083652e064a23593ff00da8616813..bc84734190937a8882583b165a72fc521dbb535f 100644 (file)
@@ -20,6 +20,7 @@ import java.util.Set;
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectName;
 import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.util.BeanReader;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
@@ -262,7 +263,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
 
     public static Map<String/* Namespace from yang file */,
             Map<String /* Name of module entry from yang file */, ModuleConfig>> transformMbeToModuleConfigs
-    (final ConfigRegistryClient configRegistryClient, Map<String/* Namespace from yang file */,
+    (final BeanReader configRegistryClient, Map<String/* Namespace from yang file */,
                     Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> mBeanEntries) {
 
         Map<String, Map<String, ModuleConfig>> namespaceToModuleNameToModuleConfig = Maps.newHashMap();
@@ -295,7 +296,6 @@ public class EditConfig extends AbstractConfigNetconfOperation {
 
     @Override
     protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
-
         EditConfigXmlParser.EditConfigExecution editConfigExecution;
         Config cfg = getConfigMapping(getConfigRegistryClient(), yangStoreSnapshot);
         editConfigExecution = editConfigXmlParser.fromXml(xml, cfg);
index 27d53cdc32c400718da6c2da3a71057a76db063c..fe7f2773cd3e0c37c04e6b93d3a83e67e676767e 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Map;
 import java.util.Set;
 import javax.management.ObjectName;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -27,6 +28,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.operations.Abs
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Datastore;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
 import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
@@ -38,12 +40,14 @@ import org.w3c.dom.Element;
 
 public class Get extends AbstractConfigNetconfOperation {
 
+    private final TransactionProvider transactionProvider;
     private final YangStoreContext yangStoreSnapshot;
     private static final Logger LOG = LoggerFactory.getLogger(Get.class);
 
-    public Get(YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
+    public Get(final TransactionProvider transactionProvider, YangStoreContext yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
                String netconfSessionIdForReporting) {
         super(configRegistryClient, netconfSessionIdForReporting);
+        this.transactionProvider = transactionProvider;
         this.yangStoreSnapshot = yangStoreSnapshot;
     }
 
@@ -115,23 +119,30 @@ public class Get extends AbstractConfigNetconfOperation {
     protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
         checkXml(xml);
 
-        final Set<ObjectName> runtimeBeans = getConfigRegistryClient().lookupRuntimeBeans();
+        final ObjectName testTransaction = transactionProvider.getOrCreateReadTransaction();
+        final ConfigTransactionClient registryClient = getConfigRegistryClient().getConfigTransactionClient(testTransaction);
 
-        //Transaction provider required only for candidate datastore
-        final Set<ObjectName> configBeans = Datastore.getInstanceQueryStrategy(Datastore.running, null)
-                .queryInstances(getConfigRegistryClient());
+        try {
+            // Runtime beans are not parts of transactions and have to be queried against the central registry
+            final Set<ObjectName> runtimeBeans = getConfigRegistryClient().lookupRuntimeBeans();
 
-        final Map<String, Map<String, ModuleRuntime>> moduleRuntimes = createModuleRuntimes(getConfigRegistryClient(),
-                yangStoreSnapshot.getModuleMXBeanEntryMap());
-        final Map<String, Map<String, ModuleConfig>> moduleConfigs = EditConfig.transformMbeToModuleConfigs(
-                getConfigRegistryClient(), yangStoreSnapshot.getModuleMXBeanEntryMap());
+            final Set<ObjectName> configBeans = Datastore.getInstanceQueryStrategy(Datastore.running, transactionProvider)
+                    .queryInstances(getConfigRegistryClient());
 
-        final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
+            final Map<String, Map<String, ModuleRuntime>> moduleRuntimes = createModuleRuntimes(getConfigRegistryClient(),
+                    yangStoreSnapshot.getModuleMXBeanEntryMap());
+            final Map<String, Map<String, ModuleConfig>> moduleConfigs = EditConfig.transformMbeToModuleConfigs(
+                    registryClient, yangStoreSnapshot.getModuleMXBeanEntryMap());
 
-        final Element element = runtime.toXml(runtimeBeans, configBeans, document);
+            final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
 
-        LOG.trace("{} operation successful", XmlNetconfConstants.GET);
+            final Element element = runtime.toXml(runtimeBeans, configBeans, document);
 
-        return element;
+            LOG.trace("{} operation successful", XmlNetconfConstants.GET);
+
+            return element;
+        } finally {
+            transactionProvider.closeReadTransaction();
+        }
     }
 }
index 350ace5eb1a44ac88bd60ac3fc338babcc4d22ae..2c4bde0ee8ffdaa3a57824fa23c89228a1f6345b 100644 (file)
@@ -72,23 +72,36 @@ public class GetConfig extends AbstractConfigNetconfOperation {
 
     private Element getResponseInternal(final Document document, final ConfigRegistryClient configRegistryClient,
             final Datastore source) {
-        Element dataElement = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
-        final Set<ObjectName> instances = Datastore.getInstanceQueryStrategy(source, this.transactionProvider)
-                .queryInstances(configRegistryClient);
 
-        final Config configMapping = new Config(EditConfig.transformMbeToModuleConfigs(configRegistryClient,
-                yangStoreSnapshot.getModuleMXBeanEntryMap()));
-
-
-        ObjectName on = transactionProvider.getOrCreateTransaction();
-        ConfigTransactionClient ta = configRegistryClient.getConfigTransactionClient(on);
-
-        ServiceRegistryWrapper serviceTracker = new ServiceRegistryWrapper(ta);
-        dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker);
-
-        LOG.trace("{} operation successful", GET_CONFIG);
-
-        return dataElement;
+        final ConfigTransactionClient registryClient;
+        // Read current state from a transaction, if running is source, then start new transaction just for reading
+        // in case of candidate, get current transaction representing candidate
+        if(source == Datastore.running) {
+            final ObjectName readTx = transactionProvider.getOrCreateReadTransaction();
+            registryClient = getConfigRegistryClient().getConfigTransactionClient(readTx);
+        } else {
+            registryClient  = getConfigRegistryClient().getConfigTransactionClient(transactionProvider.getOrCreateTransaction());
+        }
+
+        try {
+            Element dataElement = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
+            final Set<ObjectName> instances = Datastore.getInstanceQueryStrategy(source, this.transactionProvider)
+                    .queryInstances(configRegistryClient);
+
+            final Config configMapping = new Config(EditConfig.transformMbeToModuleConfigs(registryClient,
+                    yangStoreSnapshot.getModuleMXBeanEntryMap()));
+
+            ServiceRegistryWrapper serviceTracker = new ServiceRegistryWrapper(registryClient);
+            dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker);
+
+            LOG.trace("{} operation successful", GET_CONFIG);
+
+            return dataElement;
+        } finally {
+            if(source == Datastore.running) {
+                transactionProvider.closeReadTransaction();
+            }
+        }
     }
 
     @Override
index ae9cb2eb379063fd5cb2d255d85e2e54ead45500..74b5f60a101c88467a9b180cf6bc0d3d4910c67e 100644 (file)
@@ -11,12 +11,22 @@ package org.opendaylight.controller.netconf.confignetconfconnector.operations.ge
 import java.util.Set;
 import javax.management.ObjectName;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
+import org.opendaylight.controller.config.util.ConfigTransactionClient;
+import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 
 public class RunningDatastoreQueryStrategy implements DatastoreQueryStrategy {
 
+    private final TransactionProvider transactionProvider;
+
+    public RunningDatastoreQueryStrategy(TransactionProvider transactionProvider) {
+        this.transactionProvider = transactionProvider;
+    }
+
     @Override
     public Set<ObjectName> queryInstances(ConfigRegistryClient configRegistryClient) {
-        return configRegistryClient.lookupConfigBeans();
+        ObjectName on = transactionProvider.getOrCreateReadTransaction();
+        ConfigTransactionClient proxy = configRegistryClient.getConfigTransactionClient(on);
+        return proxy.lookupConfigBeans();
     }
 
 }
index 612bd859983ec99d3432a2a32894ecd8ab6b5eee..e3fdc056d9d77d482adfe53aa513618ba720566e 100644 (file)
@@ -52,7 +52,7 @@ final class NetconfOperationProvider {
         ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new Lock(netconfSessionIdForReporting));
         ops.add(new UnLock(netconfSessionIdForReporting));
-        ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
+        ops.add(new Get(transactionProvider, yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new RuntimeRpc(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
index 82c04a50e09c9124773d565fc58f2e82b17cd9ff..590f4c4ceb038b2a70f72c2379d5e759bc285db6 100644 (file)
@@ -8,10 +8,19 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
 
+import com.google.common.base.Optional;
 import java.lang.management.ManagementFactory;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 import javax.management.MBeanServer;
 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.yangtools.yang.model.api.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,4 +77,117 @@ public class NetconfOperationServiceFactoryImpl implements NetconfOperationServi
     public NetconfOperationServiceImpl createService(String netconfSessionIdForReporting) {
         return new NetconfOperationServiceImpl(yangStoreService, jmxClient, netconfSessionIdForReporting);
     }
+
+
+    @Override
+    public Set<Capability> getCapabilities() {
+        return setupCapabilities(yangStoreService);
+    }
+
+    @Override
+    public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+        return yangStoreService.registerCapabilityListener(listener);
+    }
+
+    public static Set<Capability> setupCapabilities(final YangStoreContext yangStoreSnapshot) {
+        Set<Capability> capabilities = new HashSet<>();
+        // [RFC6241] 8.3.  Candidate Configuration Capability
+        capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
+
+        // TODO rollback on error not supported EditConfigXmlParser:100
+        // [RFC6241] 8.5.  Rollback-on-Error Capability
+        // capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
+
+        Set<Module> modules = yangStoreSnapshot.getModules();
+        for (Module module : modules) {
+            capabilities.add(new YangStoreCapability(module, yangStoreSnapshot.getModuleSource(module)));
+        }
+
+        return capabilities;
+    }
+
+    private static class BasicCapability implements Capability {
+
+        private final String capability;
+
+        private BasicCapability(final String capability) {
+            this.capability = capability;
+        }
+
+        @Override
+        public String getCapabilityUri() {
+            return capability;
+        }
+
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<String> getModuleName() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<String> getRevision() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<String> getCapabilitySchema() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Collection<String> getLocation() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public String toString() {
+            return capability;
+        }
+    }
+
+    static final class YangStoreCapability extends BasicCapability {
+
+        private final String content;
+        private final String revision;
+        private final String moduleName;
+        private final String moduleNamespace;
+
+        public YangStoreCapability(final Module module, final String moduleContent) {
+            super(toCapabilityURI(module));
+            this.content = moduleContent;
+            this.moduleName = module.getName();
+            this.moduleNamespace = module.getNamespace().toString();
+            this.revision = Util.writeDate(module.getRevision());
+        }
+
+        @Override
+        public Optional<String> getCapabilitySchema() {
+            return Optional.of(content);
+        }
+
+        private static String toCapabilityURI(final Module module) {
+            return String.valueOf(module.getNamespace()) + "?module="
+                    + module.getName() + "&revision=" + Util.writeDate(module.getRevision());
+        }
+
+        @Override
+        public Optional<String> getModuleName() {
+            return Optional.of(moduleName);
+        }
+
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.of(moduleNamespace);
+        }
+
+        @Override
+        public Optional<String> getRevision() {
+            return Optional.of(revision);
+        }
+    }
 }
index ef0a72c0f05f44bc2d040a1a03ea0fe2c1af1d0a..28001851ccf2695b0d9ed69c98a6871e6e0ba7f4 100644 (file)
@@ -8,18 +8,11 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
 
-import com.google.common.base.Optional;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.Set;
 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.yangtools.yang.model.api.Module;
 
 /**
  * Manages life cycle of {@link YangStoreContext}.
@@ -28,132 +21,23 @@ public class NetconfOperationServiceImpl implements NetconfOperationService {
 
     private final NetconfOperationProvider operationProvider;
     private final TransactionProvider transactionProvider;
-    private final YangStoreService yangStoreService;
 
     public NetconfOperationServiceImpl(final YangStoreService yangStoreService, final ConfigRegistryJMXClient jmxClient,
             final String netconfSessionIdForReporting) {
 
-        this.yangStoreService = yangStoreService;
-
         transactionProvider = new TransactionProvider(jmxClient, netconfSessionIdForReporting);
         operationProvider = new NetconfOperationProvider(yangStoreService, jmxClient, transactionProvider,
                 netconfSessionIdForReporting);
     }
 
-    @Override
-    public void close() {
-        transactionProvider.close();
-    }
-
-    @Override
-    public Set<Capability> getCapabilities() {
-        return setupCapabilities(yangStoreService);
-    }
-
     @Override
     public Set<NetconfOperation> getNetconfOperations() {
         return operationProvider.getOperations();
     }
 
-    private static Set<Capability> setupCapabilities(final YangStoreContext yangStoreSnapshot) {
-        Set<Capability> capabilities = new HashSet<>();
-        // [RFC6241] 8.3.  Candidate Configuration Capability
-        capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
-
-        // TODO rollback on error not supported EditConfigXmlParser:100
-        // [RFC6241] 8.5.  Rollback-on-Error Capability
-        // capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
-
-        Set<Module> modules = yangStoreSnapshot.getModules();
-        for (Module module : modules) {
-            capabilities.add(new YangStoreCapability(module, yangStoreSnapshot.getModuleSource(module)));
-        }
-
-        return capabilities;
-    }
-
-    private static class BasicCapability implements Capability {
-
-        private final String capability;
-
-        private BasicCapability(final String capability) {
-            this.capability = capability;
-        }
-
-        @Override
-        public String getCapabilityUri() {
-            return capability;
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Collection<String> getLocation() {
-            return Collections.emptyList();
-        }
-
-        @Override
-        public String toString() {
-            return capability;
-        }
+    @Override
+    public void close() {
+        transactionProvider.close();
     }
 
-    private static final class YangStoreCapability extends BasicCapability {
-
-        private final String content;
-        private final String revision;
-        private final String moduleName;
-        private final String moduleNamespace;
-
-        public YangStoreCapability(final Module module, final String moduleContent) {
-            super(toCapabilityURI(module));
-            this.content = moduleContent;
-            this.moduleName = module.getName();
-            this.moduleNamespace = module.getNamespace().toString();
-            this.revision = Util.writeDate(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.of(content);
-        }
-
-        private static String toCapabilityURI(final Module module) {
-            return String.valueOf(module.getNamespace()) + "?module="
-                    + module.getName() + "&revision=" + Util.writeDate(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.of(moduleName);
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.of(moduleNamespace);
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.of(revision);
-        }
-    }
 }
index de151a896991f9ffc12a97df1a6bf41ece5e92a9..176800fb975ba2dd7dc7fe05ad0ca03ffb301a3b 100644 (file)
@@ -14,6 +14,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import java.lang.ref.SoftReference;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
@@ -21,6 +22,8 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicReference;
 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.notifications.BaseNetconfNotificationListener;
 import org.opendaylight.controller.netconf.notifications.BaseNotificationPublisherRegistration;
 import org.opendaylight.controller.netconf.notifications.NetconfNotificationCollector;
@@ -77,6 +80,8 @@ public class YangStoreService implements YangStoreContext {
         }
     });
 
+    private final Set<CapabilityListener> listeners = Collections.synchronizedSet(new HashSet<CapabilityListener>());
+
     public YangStoreService(final SchemaContextProvider schemaContextProvider, final BundleContext context) {
         this(schemaContextProvider, new NotificationCollectorTracker(context));
     }
@@ -130,7 +135,31 @@ public class YangStoreService implements YangStoreContext {
         notificationExecutor.submit(new CapabilityChangeNotifier(previous));
     }
 
+    public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+        if(ref.get() == null || ref.get().get() == null) {
+            getYangStoreSnapshot();
+        }
+
+        this.listeners.add(listener);
+        listener.onCapabilitiesAdded(NetconfOperationServiceFactoryImpl.setupCapabilities(ref.get().get()));
+
+        return new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                YangStoreService.this.listeners.remove(listener);
+            }
+        };
+    }
+
+    private static final Function<Module, Capability> MODULE_TO_CAPABILITY = new Function<Module, Capability>() {
+        @Override
+        public Capability apply(final Module module) {
+            return new NetconfOperationServiceFactoryImpl.YangStoreCapability(module, module.getSource());
+        }
+    };
+
     private final class CapabilityChangeNotifier implements Runnable {
+
         private final YangStoreSnapshot previous;
 
         public CapabilityChangeNotifier(final YangStoreSnapshot previous) {
@@ -142,7 +171,19 @@ public class YangStoreService implements YangStoreContext {
             final YangStoreContext current = getYangStoreSnapshot();
 
             if(current.equals(previous) == false) {
-                notificationPublisher.onCapabilityChanged(computeDiff(previous, current));
+                final Sets.SetView<Module> removed = Sets.difference(previous.getModules(), current.getModules());
+                final Sets.SetView<Module> added = Sets.difference(current.getModules(), previous.getModules());
+
+                // Notify notification manager
+                notificationPublisher.onCapabilityChanged(computeDiff(removed, added));
+
+                // Notify direct capability listener TODO would it not be better if the capability listeners went through notification manager ?
+                for (final CapabilityListener listener : listeners) {
+                    listener.onCapabilitiesAdded(Sets.newHashSet(Collections2.transform(added, MODULE_TO_CAPABILITY)));
+                }
+                for (final CapabilityListener listener : listeners) {
+                    listener.onCapabilitiesRemoved(Sets.newHashSet(Collections2.transform(removed, MODULE_TO_CAPABILITY)));
+                }
             }
         }
     }
@@ -150,15 +191,11 @@ public class YangStoreService implements YangStoreContext {
     private static final Function<Module, Uri> MODULE_TO_URI = new Function<Module, Uri>() {
         @Override
         public Uri apply(final Module input) {
-            final QName qName = QName.cachedReference(QName.create(input.getQNameModule(), input.getName()));
-            return new Uri(qName.toString());
+            return new Uri(new NetconfOperationServiceFactoryImpl.YangStoreCapability(input, input.getSource()).getCapabilityUri());
         }
     };
 
-    static NetconfCapabilityChange computeDiff(final YangStoreContext previous, final YangStoreContext current) {
-        final Sets.SetView<Module> removed = Sets.difference(previous.getModules(), current.getModules());
-        final Sets.SetView<Module> added = Sets.difference(current.getModules(), previous.getModules());
-
+    static NetconfCapabilityChange computeDiff(final Sets.SetView<Module> removed, final Sets.SetView<Module> added) {
         final NetconfCapabilityChangeBuilder netconfCapabilityChangeBuilder = new NetconfCapabilityChangeBuilder();
         netconfCapabilityChangeBuilder.setChangedBy(new ChangedByBuilder().setServerOrUser(new ServerBuilder().setServer(true).build()).build());
         netconfCapabilityChangeBuilder.setDeletedCapability(Lists.newArrayList(Collections2.transform(removed, MODULE_TO_URI)));
index b2ee63a987836102fa31ae8c97e8dac899a33198..7655cb300db5a9f28238802e59db3cf3f6a54cff 100644 (file)
@@ -31,7 +31,8 @@ public class TransactionProvider implements AutoCloseable {
     private final ConfigRegistryClient configRegistryClient;
 
     private final String netconfSessionIdForReporting;
-    private ObjectName transaction;
+    private ObjectName candidateTx;
+    private ObjectName readTx;
     private final List<ObjectName> allOpenedTransactions = new ArrayList<>();
     private static final String  NO_TRANSACTION_FOUND_FOR_SESSION = "No transaction found for session ";
 
@@ -56,18 +57,34 @@ public class TransactionProvider implements AutoCloseable {
 
     public synchronized Optional<ObjectName> getTransaction() {
 
-        if (transaction == null){
+        if (candidateTx == null){
             return Optional.absent();
         }
 
         // Transaction was already closed somehow
-        if (!isStillOpenTransaction(transaction)) {
-            LOG.warn("Fixing illegal state: transaction {} was closed in {}", transaction,
+        if (!isStillOpenTransaction(candidateTx)) {
+            LOG.warn("Fixing illegal state: transaction {} was closed in {}", candidateTx,
                     netconfSessionIdForReporting);
-            transaction = null;
+            candidateTx = null;
             return Optional.absent();
         }
-        return Optional.of(transaction);
+        return Optional.of(candidateTx);
+    }
+
+    public synchronized Optional<ObjectName> getReadTransaction() {
+
+        if (readTx == null){
+            return Optional.absent();
+        }
+
+        // Transaction was already closed somehow
+        if (!isStillOpenTransaction(readTx)) {
+            LOG.warn("Fixing illegal state: transaction {} was closed in {}", readTx,
+                    netconfSessionIdForReporting);
+            readTx = null;
+            return Optional.absent();
+        }
+        return Optional.of(readTx);
     }
 
     private boolean isStillOpenTransaction(ObjectName transaction) {
@@ -80,9 +97,20 @@ public class TransactionProvider implements AutoCloseable {
         if (ta.isPresent()) {
             return ta.get();
         }
-        transaction = configRegistryClient.beginConfig();
-        allOpenedTransactions.add(transaction);
-        return transaction;
+        candidateTx = configRegistryClient.beginConfig();
+        allOpenedTransactions.add(candidateTx);
+        return candidateTx;
+    }
+
+    public synchronized ObjectName getOrCreateReadTransaction() {
+        Optional<ObjectName> ta = getReadTransaction();
+
+        if (ta.isPresent()) {
+            return ta.get();
+        }
+        readTx = configRegistryClient.beginConfig();
+        allOpenedTransactions.add(readTx);
+        return readTx;
     }
 
     /**
@@ -109,8 +137,8 @@ public class TransactionProvider implements AutoCloseable {
         try {
             CommitStatus status = configRegistryClient.commitConfig(taON);
             // clean up
-            allOpenedTransactions.remove(transaction);
-            transaction = null;
+            allOpenedTransactions.remove(candidateTx);
+            candidateTx = null;
             return status;
         } catch (ValidationException validationException) {
             // no clean up: user can reconfigure and recover this transaction
@@ -131,8 +159,19 @@ public class TransactionProvider implements AutoCloseable {
 
         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
         transactionClient.abortConfig();
-        allOpenedTransactions.remove(transaction);
-        transaction = null;
+        allOpenedTransactions.remove(candidateTx);
+        candidateTx = null;
+    }
+
+    public synchronized void closeReadTransaction() {
+        LOG.debug("Closing read transaction");
+        Optional<ObjectName> taON = getReadTransaction();
+        Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
+
+        ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
+        transactionClient.abortConfig();
+        allOpenedTransactions.remove(readTx);
+        readTx = null;
     }
 
     public synchronized void abortTestTransaction(ObjectName testTx) {
index fdae71a16b42160aee37d9bfb9aff95e593ab115..d6b5e62b27b59eb60e023c64603e56474145592d 100644 (file)
@@ -95,8 +95,8 @@ import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStore
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
@@ -141,7 +141,9 @@ public class NetconfMappingTest extends AbstractConfigTest {
     @Mock
     NetconfOperationRouter netconfOperationRouter;
     @Mock
-    NetconfOperationServiceSnapshotImpl netconfOperationServiceSnapshot;
+    AggregatedNetconfOperationServiceFactory netconfOperationServiceSnapshot;
+    @Mock
+    private AutoCloseable sessionCloseable;
 
     private TransactionProvider transactionProvider;
 
@@ -157,13 +159,12 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
         doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
         doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
-        doNothing().when(netconfOperationServiceSnapshot).close();
 
         this.factory = new NetconfTestImplModuleFactory();
         this.factory2 = new DepTestImplModuleFactory();
         this.factory3 = new IdentityTestModuleFactory();
         factory4 = new TestImplModuleFactory();
-
+        doNothing().when(sessionCloseable).close();
 
         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, this.factory, this.factory2,
                 this.factory3, factory4));
@@ -376,7 +377,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
         edit("netconfMessages/editConfig_none.xml");
         closeSession();
-        verify(netconfOperationServiceSnapshot).close();
+        verify(sessionCloseable).close();
         verifyNoMoreInteractions(netconfOperationRouter);
         verifyNoMoreInteractions(netconfOperationServiceSnapshot);
     }
@@ -390,7 +391,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
     private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
             IOException {
-        DefaultCloseSession closeOp = new DefaultCloseSession(NETCONF_SESSION_ID, netconfOperationServiceSnapshot);
+        DefaultCloseSession closeOp = new DefaultCloseSession(NETCONF_SESSION_ID, sessionCloseable);
         executeOp(closeOp, "netconfMessages/closeSession.xml");
     }
 
@@ -715,7 +716,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
     }
 
     private Document get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
-        Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+        Get getOp = new Get(transactionProvider, yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
         return executeOp(getOp, "netconfMessages/get.xml");
     }
 
index 0aebc68bbe3f653d9a738a3ec6121ee0c162d2a9..22b061a1285c88d0ea372a5c104a2baf69fcb58c 100644 (file)
@@ -33,10 +33,10 @@ import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.persist.api.ConfigPusher;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
@@ -177,20 +177,20 @@ public class ConfigPusherImpl implements ConfigPusher {
         } catch(RuntimeException e) {
             throw new NotEnoughCapabilitiesException("Netconf service not stable for " + idForReporting, e);
         }
-        Set<String> notFoundDiff = computeNotFoundCapabilities(expectedCapabilities, serviceCandidate);
+        Set<String> notFoundDiff = computeNotFoundCapabilities(expectedCapabilities, configNetconfConnector);
         if (notFoundDiff.isEmpty()) {
             return serviceCandidate;
         } else {
             serviceCandidate.close();
             LOG.trace("Netconf server did not provide required capabilities for {} ", idForReporting,
                     "Expected but not found: {}, all expected {}, current {}",
-                     notFoundDiff, expectedCapabilities, serviceCandidate.getCapabilities()
+                     notFoundDiff, expectedCapabilities, configNetconfConnector.getCapabilities()
             );
             throw new NotEnoughCapabilitiesException("Not enough capabilities for " + idForReporting + ". Expected but not found: " + notFoundDiff);
         }
     }
 
-    private static Set<String> computeNotFoundCapabilities(Set<String> expectedCapabilities, NetconfOperationService serviceCandidate) {
+    private static Set<String> computeNotFoundCapabilities(Set<String> expectedCapabilities, NetconfOperationServiceFactory serviceCandidate) {
         Collection<String> actual = Collections2.transform(serviceCandidate.getCapabilities(), new Function<Capability, String>() {
             @Override
             public String apply(@Nonnull final Capability input) {
index 787f8b10b077612c544a6efcaad813c304ce0c9f..b27bec3c83801a275810e689e0daabbd7b458f47 100644 (file)
@@ -13,10 +13,10 @@ import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import javax.management.MBeanServer;
 import org.opendaylight.controller.config.persist.api.ConfigPusher;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPusherImpl;
 import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
@@ -70,7 +70,7 @@ public class ConfigPersisterActivator implements BundleActivator {
         InnerCustomizer innerCustomizer = new InnerCustomizer(configs, maxWaitForCapabilitiesMillis,
                 conflictingVersionTimeoutMillis, persisterAggregator);
         OuterCustomizer outerCustomizer = new OuterCustomizer(context, innerCustomizer);
-        new ServiceTracker<>(context, NetconfOperationProvider.class, outerCustomizer).open();
+        new ServiceTracker<>(context, NetconfOperationServiceFactory.class, outerCustomizer).open();
     }
 
     private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) {
@@ -103,7 +103,7 @@ public class ConfigPersisterActivator implements BundleActivator {
                 ")";
     }
 
-    class OuterCustomizer implements ServiceTrackerCustomizer<NetconfOperationProvider, NetconfOperationProvider> {
+    class OuterCustomizer implements ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> {
         private final BundleContext context;
         private final InnerCustomizer innerCustomizer;
 
@@ -113,7 +113,7 @@ public class ConfigPersisterActivator implements BundleActivator {
         }
 
         @Override
-        public NetconfOperationProvider addingService(ServiceReference<NetconfOperationProvider> reference) {
+        public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
             LOG.trace("Got OuterCustomizer.addingService {}", reference);
             // JMX was registered, track config-netconf-connector
             Filter filter;
@@ -127,12 +127,12 @@ public class ConfigPersisterActivator implements BundleActivator {
         }
 
         @Override
-        public void modifiedService(ServiceReference<NetconfOperationProvider> reference, NetconfOperationProvider service) {
+        public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
 
         }
 
         @Override
-        public void removedService(ServiceReference<NetconfOperationProvider> reference, NetconfOperationProvider service) {
+        public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
 
         }
     }
@@ -141,7 +141,9 @@ public class ConfigPersisterActivator implements BundleActivator {
         private final List<ConfigSnapshotHolder> configs;
         private final PersisterAggregator persisterAggregator;
         private final long maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis;
-
+        // This inner customizer has its filter to find the right operation service, but it gets triggered after any
+        // operation service appears. This means that it could start pushing thread up to N times (N = number of operation services spawned in OSGi)
+        private final AtomicBoolean alreadyStarted = new AtomicBoolean(false);
 
         InnerCustomizer(List<ConfigSnapshotHolder> configs, long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis,
                         PersisterAggregator persisterAggregator) {
@@ -153,6 +155,10 @@ public class ConfigPersisterActivator implements BundleActivator {
 
         @Override
         public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
+            if(alreadyStarted.compareAndSet(false, true) == false) {
+                //Prevents multiple calls to this method spawning multiple pushing threads
+                return reference.getBundle().getBundleContext().getService(reference);
+            }
             LOG.trace("Got InnerCustomizer.addingService {}", reference);
             NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
 
@@ -196,10 +202,12 @@ public class ConfigPersisterActivator implements BundleActivator {
 
         @Override
         public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
+            LOG.trace("Got InnerCustomizer.modifiedService {}", reference);
         }
 
         @Override
         public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
+            LOG.trace("Got InnerCustomizer.removedService {}", reference);
         }
 
     }
index 142d8f5226d0f7141336dcfc181428f59bd0bf42..7b79e41f380af45f8a41a1347b8816516fe8bc32 100644 (file)
@@ -20,8 +20,8 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
@@ -41,9 +41,10 @@ public class ConfigPersisterTest {
     private TestingExceptionHandler handler;
 
 
-    private void setUpContextAndStartPersister(String requiredCapability) throws Exception {
+    private void setUpContextAndStartPersister(String requiredCapability, final NetconfOperationService conflictingService) throws Exception {
         DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
         ctx = new MockedBundleContext(1000, 1000);
+        doReturn(getConflictingService()).when(ctx.serviceFactory).createService(anyString());
         configPersisterActivator = new ConfigPersisterActivator();
         configPersisterActivator.start(ctx.getBundleContext());
     }
@@ -62,7 +63,7 @@ public class ConfigPersisterTest {
 
     @Test
     public void testPersisterNotAllCapabilitiesProvided() throws Exception {
-        setUpContextAndStartPersister("required-cap");
+        setUpContextAndStartPersister("required-cap", getConflictingService());
         Thread.sleep(2000);
         handler.assertException(IllegalStateException.class, "Max wait for capabilities reached.Not enough capabilities " +
                 "for <data><config-snapshot/></data>. Expected but not found: [required-cap]");
@@ -71,7 +72,7 @@ public class ConfigPersisterTest {
 
     @Test
     public void testPersisterSuccessfulPush() throws Exception {
-        setUpContextAndStartPersister("cap1");
+        setUpContextAndStartPersister("cap1", getConflictingService());
         NetconfOperationService service = getWorkingService(getOKDocument());
         doReturn(service).when(ctx.serviceFactory).createService(anyString());
         Thread.sleep(2000);
@@ -86,7 +87,7 @@ public class ConfigPersisterTest {
     public NetconfOperationService getWorkingService(Document document) throws SAXException, IOException, NetconfDocumentedException {
         NetconfOperationService service = mock(NetconfOperationService.class);
         Capability capability = mock(Capability.class);
-        doReturn(Sets.newHashSet(capability)).when(service).getCapabilities();
+//        doReturn(Sets.newHashSet(capability)).when(service).getCapabilities();
         doReturn("cap1").when(capability).getCapabilityUri();
 
 
@@ -109,9 +110,8 @@ public class ConfigPersisterTest {
 
     @Test
     public void testPersisterConflictingVersionException() throws Exception {
-        setUpContextAndStartPersister("cap1");
+        setUpContextAndStartPersister("cap1", getConflictingService());
 
-        doReturn(getConflictingService()).when(ctx.serviceFactory).createService(anyString());
         Thread.sleep(2000);
         handler.assertException(IllegalStateException.class, "Max wait for conflicting version stabilization timeout");
     }
@@ -131,7 +131,7 @@ public class ConfigPersisterTest {
 
     @Test
     public void testSuccessConflictingVersionException() throws Exception {
-        setUpContextAndStartPersister("cap1");
+        setUpContextAndStartPersister("cap1", getConflictingService());
         doReturn(getConflictingService()).when(ctx.serviceFactory).createService(anyString());
         Thread.sleep(500);
         // working service:
index 0d866ecda7ee7349c1f470be5b110a3ab4a9376b..bd18c8c30e8791dc08a5e6e4a3eceb82a1f7de6c 100644 (file)
@@ -12,6 +12,7 @@ import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -28,7 +29,7 @@ import org.opendaylight.controller.config.persist.api.ConfigPusher;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.persist.impl.DummyAdapter;
@@ -60,11 +61,11 @@ final class MockedBundleContext {
         doReturn(null).when(context).getProperty(anyString());
         initContext(maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
 
-        String outerFilterString = "(objectClass=org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider)";
+        String outerFilterString = "(objectClass=org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory)";
         doReturn(outerFilter).when(context).createFilter(outerFilterString);
         doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(outerFilterString));
         ServiceReference<?>[] toBeReturned = {serviceReference};
-        doReturn(toBeReturned).when(context).getServiceReferences(NetconfOperationProvider.class.getName(), null);
+        doReturn(toBeReturned).when(context).getServiceReferences(NetconfOperationServiceFactory.class.getName(), null);
 
         String innerFilterString = "innerfilter";
         doReturn(innerFilterString).when(outerFilter).toString();
@@ -77,9 +78,12 @@ final class MockedBundleContext {
         doReturn(bundle).when(serviceReference).getBundle();
         doReturn(context).when(bundle).getBundleContext();
         doReturn("").when(serviceReference).toString();
+        doReturn("context").when(context).toString();
         doReturn(serviceFactory).when(context).getService(any(ServiceReference.class));
         doReturn(service).when(serviceFactory).createService(anyString());
-        doReturn(Collections.emptySet()).when(service).getCapabilities();
+        final Capability cap = mock(Capability.class);
+        doReturn("cap1").when(cap).getCapabilityUri();
+        doReturn(Collections.singleton(cap)).when(serviceFactory).getCapabilities();
         doNothing().when(service).close();
         doReturn("serviceFactoryMock").when(serviceFactory).toString();
 
index b4ad89b55867a78b25d08f8682d438aee82f7e38..84756fc7135acae05a1aeccb7aed726a9027bf65 100644 (file)
@@ -9,7 +9,9 @@ module ietf-netconf-monitoring {
 
     import ietf-yang-types {
       prefix yang;
+      revision-date "2010-09-24";
     }
+
     import ietf-inet-types {
       prefix inet;
     }
index ccf751285a39c5675eaee79c5ec2c346d6c903ec..bf8bdb06f31dd37c3a27bb2e8236f041fad22f4f 100644 (file)
@@ -26,7 +26,15 @@ public class NetconfMdsalMapperModule extends org.opendaylight.controller.config
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency(), getDomBrokerDependency());
+        final MdsalNetconfOperationServiceFactory mdsalNetconfOperationServiceFactory = new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency(), getDomBrokerDependency()) {
+            @Override
+            public void close() throws Exception {
+                super.close();
+                getMapperAggregatorDependency().onRemoveNetconfOperationServiceFactory(this);
+            }
+        };
+        getMapperAggregatorDependency().onAddNetconfOperationServiceFactory(mdsalNetconfOperationServiceFactory);
+        return mdsalNetconfOperationServiceFactory;
     }
 
 }
index df671e8f4f2ab07fd38e31d7cda55c2736f04f8b..1aa38eb80c0a1fab17ea8512cacce4bf83fd1fe7 100644 (file)
@@ -9,7 +9,12 @@
 package org.opendaylight.controller.netconf.mdsal.connector;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -18,6 +23,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 public class CurrentSchemaContext implements SchemaContextListener, AutoCloseable {
     final AtomicReference<SchemaContext> currentContext = new AtomicReference<SchemaContext>();
     private final ListenerRegistration<SchemaContextListener> schemaContextListenerListenerRegistration;
+    private final Set<CapabilityListener> listeners = Collections.synchronizedSet(Sets.<CapabilityListener>newHashSet());
 
     public SchemaContext getCurrentContext() {
         Preconditions.checkState(currentContext.get() != null, "Current context not received");
@@ -31,11 +37,28 @@ public class CurrentSchemaContext implements SchemaContextListener, AutoCloseabl
     @Override
     public void onGlobalContextUpdated(final SchemaContext schemaContext) {
         currentContext.set(schemaContext);
+        // FIXME is notifying all the listeners from this callback wise ?
+        final Set<Capability> addedCaps = MdsalNetconfOperationServiceFactory.transformCapabilities(currentContext.get());
+        for (final CapabilityListener listener : listeners) {
+            listener.onCapabilitiesAdded(addedCaps);
+        }
     }
 
     @Override
     public void close() throws Exception {
+        listeners.clear();
         schemaContextListenerListenerRegistration.close();
         currentContext.set(null);
     }
+
+    public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+        listener.onCapabilitiesAdded(MdsalNetconfOperationServiceFactory.transformCapabilities(currentContext.get()));
+        listeners.add(listener);
+        return new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                listeners.remove(listener);
+            }
+        };
+    }
 }
\ No newline at end of file
index f54c5e9838b21549199633ec699e4ae953b2aaa9..cc22dd51aaa5c8bdbcaffda3ba09d2ac509a68e4 100644 (file)
@@ -8,34 +8,17 @@
 
 package org.opendaylight.controller.netconf.mdsal.connector;
 
-import com.google.common.base.Optional;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.Set;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class MdsalNetconfOperationService implements NetconfOperationService {
 
-    private static final Logger LOG = LoggerFactory.getLogger(MdsalNetconfOperationService.class);
-
-    private final CurrentSchemaContext schemaContext;
-    private final String netconfSessionIdForReporting;
     private final OperationProvider operationProvider;
 
     public MdsalNetconfOperationService(final CurrentSchemaContext schemaContext, final String netconfSessionIdForReporting,
                                         final DOMDataBroker dataBroker) {
-        this.schemaContext = schemaContext;
-        // TODO schema contexts are different in data broker and the one we receive here ... the one received here should be updated same way as broker is
-        this.netconfSessionIdForReporting = netconfSessionIdForReporting;
         this.operationProvider = new OperationProvider(netconfSessionIdForReporting, schemaContext, dataBroker);
     }
 
@@ -44,115 +27,9 @@ public class MdsalNetconfOperationService implements NetconfOperationService {
 
     }
 
-    // TODO does this get called dynamically ?
-    @Override
-    public Set<Capability> getCapabilities() {
-        final Set<Capability> capabilities = new HashSet<>();
-        // [RFC6241] 8.3.  Candidate Configuration Capability
-        capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
-
-        final SchemaContext currentContext = schemaContext.getCurrentContext();
-        final Set<Module> modules = currentContext.getModules();
-        for (final Module module : modules) {
-            if(currentContext.getModuleSource(module).isPresent()) {
-                capabilities.add(new YangStoreCapability(module, currentContext.getModuleSource(module).get()));
-            } else {
-                LOG.warn("Missing source for module {}. This module will not be available from netconf server for session {}",
-                        module, netconfSessionIdForReporting);
-            }
-        }
-
-        return capabilities;
-    }
-
     @Override
     public Set<NetconfOperation> getNetconfOperations() {
         return operationProvider.getOperations();
     }
 
-    // TODO reuse from netconf impl
-    private static class BasicCapability implements Capability {
-
-        private final String capability;
-
-        private BasicCapability(final String capability) {
-            this.capability = capability;
-        }
-
-        @Override
-        public String getCapabilityUri() {
-            return capability;
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Collection<String> getLocation() {
-            return Collections.emptyList();
-        }
-
-        @Override
-        public String toString() {
-            return capability;
-        }
-    }
-
-    private static final class YangStoreCapability extends BasicCapability {
-
-        private final String content;
-        private final String revision;
-        private final String moduleName;
-        private final String moduleNamespace;
-
-        public YangStoreCapability(final Module module, final String moduleContent) {
-            super(toCapabilityURI(module));
-            this.content = moduleContent;
-            this.moduleName = module.getName();
-            this.moduleNamespace = module.getNamespace().toString();
-            this.revision = SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.of(content);
-        }
-
-        private static String toCapabilityURI(final Module module) {
-            return String.valueOf(module.getNamespace()) + "?module="
-                    + module.getName() + "&revision=" + SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.of(moduleName);
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.of(moduleNamespace);
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.of(revision);
-        }
-    }
 }
index 098f25bf4a9216adeba96833e06d497b65cb4539..ebb0e9d3d1ac2d9bf364afcb236e151ebecb8af2 100644 (file)
@@ -8,13 +8,27 @@
 
 package org.opendaylight.controller.netconf.mdsal.connector;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class MdsalNetconfOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable {
 
+    private static final Logger LOG = LoggerFactory.getLogger(MdsalNetconfOperationServiceFactory.class);
+
     private final DOMDataBroker dataBroker;
     private final CurrentSchemaContext currentSchemaContext;
 
@@ -32,4 +46,118 @@ public class MdsalNetconfOperationServiceFactory implements NetconfOperationServ
     public void close() throws Exception {
         currentSchemaContext.close();
     }
+
+    @Override
+    public Set<Capability> getCapabilities() {
+        return transformCapabilities(currentSchemaContext.getCurrentContext());
+    }
+
+    static Set<Capability> transformCapabilities(final SchemaContext currentContext1) {
+        final Set<Capability> capabilities = new HashSet<>();
+        // [RFC6241] 8.3.  Candidate Configuration Capability
+        capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
+
+        final SchemaContext currentContext = currentContext1;
+        final Set<Module> modules = currentContext.getModules();
+        for (final Module module : modules) {
+            if(currentContext.getModuleSource(module).isPresent()) {
+                capabilities.add(new YangStoreCapability(module, currentContext.getModuleSource(module).get()));
+            } else {
+                LOG.warn("Missing source for module {}. This module will not be available from netconf server",
+                        module);
+            }
+        }
+
+        return capabilities;
+    }
+
+    @Override
+    public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+        return currentSchemaContext.registerCapabilityListener(listener);
+    }
+
+    private static class BasicCapability implements Capability {
+
+        private final String capability;
+
+        private BasicCapability(final String capability) {
+            this.capability = capability;
+        }
+
+        @Override
+        public String getCapabilityUri() {
+            return capability;
+        }
+
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<String> getModuleName() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<String> getRevision() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<String> getCapabilitySchema() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Collection<String> getLocation() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public String toString() {
+            return capability;
+        }
+    }
+
+    private static final class YangStoreCapability extends BasicCapability {
+
+        private final String content;
+        private final String revision;
+        private final String moduleName;
+        private final String moduleNamespace;
+
+        public YangStoreCapability(final Module module, final String moduleContent) {
+            super(toCapabilityURI(module));
+            this.content = moduleContent;
+            this.moduleName = module.getName();
+            this.moduleNamespace = module.getNamespace().toString();
+            this.revision = SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
+        }
+
+        @Override
+        public Optional<String> getCapabilitySchema() {
+            return Optional.of(content);
+        }
+
+        private static String toCapabilityURI(final Module module) {
+            return String.valueOf(module.getNamespace()) + "?module="
+                    + module.getName() + "&revision=" + SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
+        }
+
+        @Override
+        public Optional<String> getModuleName() {
+            return Optional.of(moduleName);
+        }
+
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.of(moduleNamespace);
+        }
+
+        @Override
+        public Optional<String> getRevision() {
+            return Optional.of(revision);
+        }
+    }
 }
index e0c004461c116c5b1bb23f41c566537e565c05ef..8f6ff417d6499d47dc594bc5ab5fb2de03e937d0 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.netconf.mdsal.connector.ops.get;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Iterables;
 import java.io.IOException;
@@ -115,13 +116,13 @@ public abstract class AbstractGet extends AbstractLastNetconfOperation {
     }
 
     protected static final class GetConfigExecution {
-        private final Datastore datastore;
+        private final Optional<Datastore> datastore;
 
-        public GetConfigExecution(final Datastore datastore) {
+        public GetConfigExecution(final Optional<Datastore> datastore) {
             this.datastore = datastore;
         }
 
-        public Datastore getDatastore() {
+        public Optional<Datastore> getDatastore() {
             return datastore;
         }
 
@@ -132,7 +133,7 @@ public abstract class AbstractGet extends AbstractLastNetconfOperation {
                 throw new NetconfDocumentedException("Incorrect RPC: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
             }
 
-            final Datastore sourceDatastore;
+            final Optional<Datastore> sourceDatastore;
             try {
                 sourceDatastore = parseSource(xml);
             } catch (final NetconfDocumentedException e) {
@@ -144,14 +145,12 @@ public abstract class AbstractGet extends AbstractLastNetconfOperation {
             return new GetConfigExecution(sourceDatastore);
         }
 
-        private static Datastore parseSource(final XmlElement xml) throws NetconfDocumentedException {
-            final Datastore sourceDatastore;
-            final XmlElement sourceElement = xml.getOnlyChildElement(XmlNetconfConstants.SOURCE_KEY,
+        private static Optional<Datastore> parseSource(final XmlElement xml) throws NetconfDocumentedException {
+            final Optional<XmlElement> sourceElement = xml.getOnlyChildElementOptionally(XmlNetconfConstants.SOURCE_KEY,
                     XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
 
-            final String sourceParsed = sourceElement.getOnlyChildElement().getName();
-            sourceDatastore = Datastore.valueOf(sourceParsed);
-            return sourceDatastore;
+            return  sourceElement.isPresent() ?
+                    Optional.of(Datastore.valueOf(sourceElement.get().getOnlyChildElement().getName())) : Optional.<Datastore>absent();
         }
 
         private static void validateInputRpc(final XmlElement xml, String operationName) throws NetconfDocumentedException{
index a2b2fbb0db0304184cdc653b34a1e5f046ee3267..cebd8c88837547f0f2d2f573ca0e2e81ed03e67a 100644 (file)
@@ -52,13 +52,10 @@ public class Get extends AbstractGet {
         }
 
         final YangInstanceIdentifier dataRoot = ROOT;
-        DOMDataReadWriteTransaction rwTx = getTransaction(getConfigExecution.getDatastore());
+        DOMDataReadWriteTransaction rwTx = getTransaction(Datastore.running);
         try {
             final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = rwTx.read(LogicalDatastoreType.OPERATIONAL, dataRoot).checkedGet();
-            if (getConfigExecution.getDatastore() == Datastore.running) {
-                transactionProvider.abortRunningTransaction(rwTx);
-                rwTx = null;
-            }
+            transactionProvider.abortRunningTransaction(rwTx);
             return (Element) transformNormalizedNode(document, normalizedNodeOptional.get(), dataRoot);
         } catch (ReadFailedException e) {
             LOG.warn("Unable to read data: {}", dataRoot, e);
index b56bcc795caf3ad1c5adacaa98d445e1b63079a8..f2d8abbb6180f10785f7cb00c59dcb6d6fd7d5ee 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.netconf.mdsal.connector.ops.get;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
@@ -52,10 +53,13 @@ public class GetConfig extends AbstractGet {
         }
 
         final YangInstanceIdentifier dataRoot = ROOT;
-        DOMDataReadWriteTransaction rwTx = getTransaction(getConfigExecution.getDatastore());
+        // Proper exception should be thrown
+        Preconditions.checkState(getConfigExecution.getDatastore().isPresent(), "Source element missing from request");
+
+        DOMDataReadWriteTransaction rwTx = getTransaction(getConfigExecution.getDatastore().get());
         try {
             final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = rwTx.read(LogicalDatastoreType.CONFIGURATION, dataRoot).checkedGet();
-            if (getConfigExecution.getDatastore() == Datastore.running) {
+            if (getConfigExecution.getDatastore().get() == Datastore.running) {
                 transactionProvider.abortRunningTransaction(rwTx);
                 rwTx = null;
             }
index b1d04106d70dd2b3f6c35a3bf614a2ed4097fda8..9d9966e8f1d5e922c193c80140297069782741ee 100644 (file)
@@ -44,6 +44,15 @@ module netconf-mdsal-mapper {
                     }
                 }
             }
+
+            container mapper-aggregator {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity nnm:netconf-mapper-registry;
+                    }
+                }
+            }
         }
     }
 
diff --git a/opendaylight/netconf/mdsal-netconf-monitoring/pom.xml b/opendaylight/netconf/mdsal-netconf-monitoring/pom.xml
new file mode 100644 (file)
index 0000000..3e78dd1
--- /dev/null
@@ -0,0 +1,99 @@
+<?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>netconf-subsystem</artifactId>
+    <version>0.3.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>mdsal-netconf-monitoring</artifactId>
+  <packaging>bundle</packaging>
+  <name>${project.artifactId}</name>
+
+  <dependencies>
+    <!-- compile dependencies -->
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-mapping-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-monitoring</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-util</artifactId>
+    </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-config</artifactId>
+      </dependency>
+
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>mockito-configuration</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+      </plugin>
+        <plugin>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-maven-plugin</artifactId>
+            <executions>
+                <execution>
+                    <id>config</id>
+                    <goals>
+                        <goal>generate-sources</goal>
+                    </goals>
+                    <configuration>
+                        <codeGenerators>
+                            <generator>
+                                <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                                <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                <additionalConfiguration>
+                                    <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+                                </additionalConfiguration>
+                            </generator>
+                            <generator>
+                                <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                            </generator>
+                        </codeGenerators>
+                        <inspectDependencies>true</inspectDependencies>
+                    </configuration>
+                </execution>
+            </executions>
+            <dependencies>
+                <dependency>
+                    <groupId>org.opendaylight.controller</groupId>
+                    <artifactId>yang-jmx-generator-plugin</artifactId>
+                    <version>${config.version}</version>
+                </dependency>
+            </dependencies>
+        </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/MonitoringToMdsalWriter.java b/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/MonitoringToMdsalWriter.java
new file mode 100644 (file)
index 0000000..50958e4
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015 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.netconf.mdsal.monitoring;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class MonitoringToMdsalWriter implements AutoCloseable, NetconfMonitoringService.MonitoringListener, BindingAwareProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MonitoringToMdsalWriter.class);
+
+    private final NetconfMonitoringService serverMonitoringDependency;
+    private DataBroker dataBroker;
+
+    public MonitoringToMdsalWriter(final NetconfMonitoringService serverMonitoringDependency) {
+        this.serverMonitoringDependency = serverMonitoringDependency;
+    }
+
+    @Override
+    public void close() {
+        final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+        tx.delete(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NetconfState.class));
+        final CheckedFuture<Void, TransactionCommitFailedException> submit = tx.submit();
+
+        Futures.addCallback(submit, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(final Void aVoid) {
+                LOG.debug("Netconf state cleared successfully");
+            }
+
+            @Override
+            public void onFailure(final Throwable throwable) {
+                LOG.warn("Unable to clear netconf state", throwable);
+            }
+        });
+    }
+
+    @Override
+    public void onStateChanged(final NetconfState state) {
+        Preconditions.checkState(dataBroker != null);
+        final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+        tx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NetconfState.class), state);
+        // FIXME first attempt (right after we register to binding broker) always fails
+        // Is it due to the fact that we are writing from the onSessionInitiated callback ?
+        final CheckedFuture<Void, TransactionCommitFailedException> submit = tx.submit();
+
+        Futures.addCallback(submit, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(final Void aVoid) {
+                LOG.debug("Netconf state updated successfully");
+            }
+
+            @Override
+            public void onFailure(final Throwable throwable) {
+                LOG.warn("Unable to update netconf state", throwable);
+            }
+        });
+    }
+
+    @Override
+    public void onSessionInitiated(final BindingAwareBroker.ProviderContext providerContext) {
+        dataBroker = providerContext.getSALService(DataBroker.class);
+        serverMonitoringDependency.registerListener(this);
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/NetconfMdsalMonitoringMapperModule.java b/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/NetconfMdsalMonitoringMapperModule.java
new file mode 100644 (file)
index 0000000..dadc0f4
--- /dev/null
@@ -0,0 +1,149 @@
+package org.opendaylight.controller.config.yang.netconf.mdsal.monitoring;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.monitoring.GetSchema;
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+
+public class NetconfMdsalMonitoringMapperModule extends org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.AbstractNetconfMdsalMonitoringMapperModule {
+    public NetconfMdsalMonitoringMapperModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetconfMdsalMonitoringMapperModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.NetconfMdsalMonitoringMapperModule oldModule, final java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        final NetconfMonitoringService serverMonitoringDependency = getServerMonitoringDependency();
+
+        final MonitoringToMdsalWriter monitoringToMdsalWriter = new MonitoringToMdsalWriter(serverMonitoringDependency);
+        getBindingAwareBrokerDependency().registerProvider(monitoringToMdsalWriter);
+
+        final MdSalMonitoringMapperFactory mdSalMonitoringMapperFactory = new MdSalMonitoringMapperFactory(new MdsalMonitoringMapper(serverMonitoringDependency)) {
+            @Override
+            public void close() {
+                super.close();
+                monitoringToMdsalWriter.close();
+                getAggregatorDependency().onRemoveNetconfOperationServiceFactory(this);
+            }
+        };
+
+        getAggregatorDependency().onAddNetconfOperationServiceFactory(mdSalMonitoringMapperFactory);
+        return mdSalMonitoringMapperFactory;
+
+    }
+
+    // FIXME almost exactly same code as in netconf-monitoring, refactor
+    private static class MdSalMonitoringMapperFactory implements NetconfOperationServiceFactory, AutoCloseable {
+
+        private final NetconfOperationService operationService;
+
+        private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
+
+            @Override
+            public String getCapabilityUri() {
+                return MonitoringConstants.URI;
+            }
+
+            @Override
+            public Optional<String> getModuleNamespace() {
+                return Optional.of(MonitoringConstants.NAMESPACE);
+            }
+
+            @Override
+            public Optional<String> getModuleName() {
+                return Optional.of(MonitoringConstants.MODULE_NAME);
+            }
+
+            @Override
+            public Optional<String> getRevision() {
+                return Optional.of(MonitoringConstants.MODULE_REVISION);
+            }
+
+            @Override
+            public Optional<String> getCapabilitySchema() {
+                return Optional.absent();
+            }
+
+            @Override
+            public Collection<String> getLocation() {
+                return Collections.emptyList();
+            }
+        });
+
+        private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                // NOOP
+            }
+        };
+
+        private final List<CapabilityListener> listeners = new ArrayList<>();
+
+        public MdSalMonitoringMapperFactory(final NetconfOperationService operationService) {
+            this.operationService = operationService;
+        }
+
+        @Override
+        public NetconfOperationService createService(final String netconfSessionIdForReporting) {
+            return operationService;
+        }
+
+        @Override
+        public Set<Capability> getCapabilities() {
+            return CAPABILITIES;
+        }
+
+        @Override
+        public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+            listener.onCapabilitiesAdded(getCapabilities());
+            listeners.add(listener);
+            return AUTO_CLOSEABLE;
+        }
+
+        @Override
+        public void close() {
+            for (final CapabilityListener listener : listeners) {
+                listener.onCapabilitiesRemoved(getCapabilities());
+            }
+        }
+    }
+
+
+    private static class MdsalMonitoringMapper implements NetconfOperationService {
+
+        private final NetconfMonitoringService serverMonitoringDependency;
+
+        public MdsalMonitoringMapper(final NetconfMonitoringService serverMonitoringDependency) {
+            this.serverMonitoringDependency = serverMonitoringDependency;
+        }
+
+        @Override
+        public Set<NetconfOperation> getNetconfOperations() {
+            return Collections.<NetconfOperation>singleton(new GetSchema(serverMonitoringDependency));
+        }
+
+        @Override
+        public void close() {
+            // NOOP
+        }
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/NetconfMdsalMonitoringMapperModuleFactory.java b/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/NetconfMdsalMonitoringMapperModuleFactory.java
new file mode 100644 (file)
index 0000000..e0d4593
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-mdsal-monitoring yang module local name: netconf-mdsal-monitoring-mapper
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 18 10:22:17 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.netconf.mdsal.monitoring;
+public class NetconfMdsalMonitoringMapperModuleFactory extends org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.AbstractNetconfMdsalMonitoringMapperModuleFactory {
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/NetconfMonitoringOperationService.java b/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/NetconfMonitoringOperationService.java
new file mode 100644 (file)
index 0000000..9ae4df4
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+* 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.monitoring;
+
+import com.google.common.collect.Sets;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.monitoring.Get;
+import org.opendaylight.controller.netconf.monitoring.GetSchema;
+
+public class NetconfMonitoringOperationService implements NetconfOperationService {
+
+    private final NetconfMonitoringService monitor;
+
+    public NetconfMonitoringOperationService(final NetconfMonitoringService monitor) {
+        this.monitor = monitor;
+    }
+
+    @Override
+    public Set<NetconfOperation> getNetconfOperations() {
+        return Sets.<NetconfOperation>newHashSet(new Get(monitor), new GetSchema(monitor));
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/NetconfMonitoringOperationServiceFactory.java b/opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/NetconfMonitoringOperationServiceFactory.java
new file mode 100644 (file)
index 0000000..78c2368
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.monitoring;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+
+/**
+* Created by mmarsale on 18.2.2015.
+*/
+public class NetconfMonitoringOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable {
+
+    private final NetconfMonitoringOperationService operationService;
+
+    private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
+
+        @Override
+        public String getCapabilityUri() {
+            return MonitoringConstants.URI;
+        }
+
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.of(MonitoringConstants.NAMESPACE);
+        }
+
+        @Override
+        public Optional<String> getModuleName() {
+            return Optional.of(MonitoringConstants.MODULE_NAME);
+        }
+
+        @Override
+        public Optional<String> getRevision() {
+            return Optional.of(MonitoringConstants.MODULE_REVISION);
+        }
+
+        @Override
+        public Optional<String> getCapabilitySchema() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Collection<String> getLocation() {
+            return Collections.emptyList();
+        }
+    });
+
+    private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
+        @Override
+        public void close() throws Exception {
+            // NOOP
+        }
+    };
+
+    private final List<CapabilityListener> listeners = new ArrayList<>();
+
+    public NetconfMonitoringOperationServiceFactory(final NetconfMonitoringOperationService operationService) {
+        this.operationService = operationService;
+    }
+
+    @Override
+    public NetconfOperationService createService(final String netconfSessionIdForReporting) {
+        return operationService;
+    }
+
+    @Override
+    public Set<Capability> getCapabilities() {
+        return CAPABILITIES;
+    }
+
+    @Override
+    public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+        listener.onCapabilitiesAdded(getCapabilities());
+        listeners.add(listener);
+        return AUTO_CLOSEABLE;
+    }
+
+    @Override
+    public void close() {
+        for (final CapabilityListener listener : listeners) {
+            listener.onCapabilitiesRemoved(getCapabilities());
+        }
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-monitoring/src/main/yang/netconf-mdsal-monitoring.yang b/opendaylight/netconf/mdsal-netconf-monitoring/src/main/yang/netconf-mdsal-monitoring.yang
new file mode 100644 (file)
index 0000000..68a248e
--- /dev/null
@@ -0,0 +1,60 @@
+module netconf-mdsal-monitoring {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring";
+    prefix "nmmonitor";
+
+    import netconf-northbound-mapper { prefix nnm; revision-date 2015-01-14; }
+    import opendaylight-md-sal-binding {prefix md-sal-binding; revision-date 2013-10-28;}
+    import netconf-northbound { prefix nn; revision-date 2015-01-14; }
+    import config { prefix config; revision-date 2013-04-05; }
+
+    organization "Cisco Systems, Inc.";
+
+    description
+        "This module contains the base YANG definitions for
+         an MD-SAL monitoring mapper implementation";
+
+    revision "2015-02-18" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-mdsal-monitoring-mapper {
+        base config:module-type;
+        config:provided-service nnm:netconf-northbound-mapper;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netconf-mdsal-monitoring-mapper {
+            when "/config:modules/config:module/config:type = 'netconf-mdsal-monitoring-mapper'";
+
+            container server-monitoring {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity nn:netconf-server-monitoring;
+                    }
+                }
+            }
+
+            container aggregator {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity nnm:netconf-mapper-registry;
+                    }
+                }
+            }
+
+            container binding-aware-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity md-sal-binding:binding-broker-osgi-registry;
+                    }
+                }
+            }
+        }
+    }
+
+}
similarity index 93%
rename from opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/Capability.java
rename to opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/Capability.java
index 408756bf4d221ac2eccde2cbb35133a7592e417f..6a061b1ea9056a5f153af79b4d0052ebb8f040a2 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.mapping.api;
+package org.opendaylight.controller.netconf.api;
 
 import com.google.common.base.Optional;
 import java.util.Collection;
diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/CapabilityListener.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/monitoring/CapabilityListener.java
new file mode 100644 (file)
index 0000000..5d9468c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 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.api.monitoring;
+
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+
+public interface CapabilityListener {
+
+    void onCapabilitiesAdded(Set<Capability> addedCaps);
+
+    void onCapabilitiesRemoved(Set<Capability> removedCaps);
+}
index 51eea9307de4ff8b22188fe9385e8da242e0544b..d22412c7cf11df2447d19a184c7c5966159a5f86 100644 (file)
@@ -7,12 +7,30 @@
  */
 package org.opendaylight.controller.netconf.api.monitoring;
 
+import com.google.common.base.Optional;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
 
-public interface NetconfMonitoringService {
+public interface NetconfMonitoringService extends CapabilityListener, SessionListener {
 
     Sessions getSessions();
 
     Schemas getSchemas();
+
+    String getSchemaForCapability(String moduleName, Optional<String> revision);
+
+    Capabilities getCapabilities();
+
+    /**
+     * Allows push based state information transfer. After the listener is registered, current state is pushed to the listener.
+     */
+    AutoCloseable registerListener(MonitoringListener listener);
+
+    interface MonitoringListener {
+
+        // TODO more granular updates would make sense
+        void onStateChanged(NetconfState state);
+    }
 }
@@ -1,16 +1,17 @@
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2015 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.impl.osgi;
 
-import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-
-public interface SessionMonitoringService {
+package org.opendaylight.controller.netconf.api.monitoring;
 
+/**
+ * Created by mmarsale on 13.2.2015.
+ */
+public interface SessionListener {
     void onSessionUp(NetconfManagementSession session);
 
     void onSessionDown(NetconfManagementSession session);
index f775da91c0456cb49d1043291feba48e2f815855..e2b0d35867832ddb87bb3c1833fada6cfcf1554c 100644 (file)
@@ -19,4 +19,9 @@ module netconf-northbound {
         config:java-class "org.opendaylight.controller.netconf.api.NetconfServerDispatcher";
     }
 
+    identity netconf-server-monitoring {
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService";
+    }
+
 }
\ No newline at end of file
index 12489339154075ae01545c2083c531cfd6e2f3e2..d27ea558126ece253720b77832a9783a13f855ee 100644 (file)
                 <artifactId>netconf-monitoring</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>mdsal-netconf-monitoring</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>netconf-netty-util</artifactId>
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfMapperAggregatorModule.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfMapperAggregatorModule.java
new file mode 100644 (file)
index 0000000..284c600
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
+
+public class NetconfMapperAggregatorModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfMapperAggregatorModule {
+    public NetconfMapperAggregatorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetconfMapperAggregatorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final org.opendaylight.controller.config.yang.config.netconf.northbound.impl.NetconfMapperAggregatorModule oldModule, final java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {}
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        return new AggregatedNetconfOperationServiceFactory();
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfMapperAggregatorModuleFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfMapperAggregatorModuleFactory.java
new file mode 100644 (file)
index 0000000..0e415bd
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-northbound-impl yang module local name: netconf-mapper-aggregator
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Tue Feb 17 17:24:19 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+public class NetconfMapperAggregatorModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfMapperAggregatorModuleFactory {
+
+}
index e64620d4ad42247ddcad43913dbefebd3b6c5bf1..3c476608a2126b7a4a60eece2a03deca71037636 100644 (file)
@@ -1,13 +1,12 @@
 package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
 
 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.impl.CommitNotifier;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 
 public class NetconfServerDispatcherModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerDispatcherModule {
@@ -27,8 +26,8 @@ public class NetconfServerDispatcherModule extends org.opendaylight.controller.c
     @Override
     public java.lang.AutoCloseable createInstance() {
 
-        final NetconfOperationServiceFactoryListenerImpl aggregatedOpProvider = getAggregatedOpProvider();
-        final SessionMonitoringService monitoringService = startMonitoringService(aggregatedOpProvider);
+        final AggregatedNetconfOperationServiceFactory aggregatedOpProvider = getAggregatedOpProvider();
+        final NetconfMonitoringService monitoringService = getServerMonitorDependency();
         final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
                 getTimerDependency(), aggregatedOpProvider, new SessionIdProvider(), getConnectionTimeoutMillis(), CommitNotifier.NoopCommitNotifier.getInstance(), monitoringService);
         final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
@@ -44,12 +43,8 @@ public class NetconfServerDispatcherModule extends org.opendaylight.controller.c
 
     }
 
-    private NetconfMonitoringServiceImpl startMonitoringService(final NetconfOperationServiceFactoryListenerImpl netconfOperationProvider) {
-        return new NetconfMonitoringServiceImpl(netconfOperationProvider);
-    }
-
-    private NetconfOperationServiceFactoryListenerImpl getAggregatedOpProvider() {
-        final NetconfOperationServiceFactoryListenerImpl netconfOperationProvider = new NetconfOperationServiceFactoryListenerImpl();
+    private AggregatedNetconfOperationServiceFactory getAggregatedOpProvider() {
+        final AggregatedNetconfOperationServiceFactory netconfOperationProvider = new AggregatedNetconfOperationServiceFactory();
         for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getMappersDependency()) {
             netconfOperationProvider.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
         }
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerMonitoringModule.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerMonitoringModule.java
new file mode 100644 (file)
index 0000000..dc18cd3
--- /dev/null
@@ -0,0 +1,24 @@
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+
+import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
+
+public class NetconfServerMonitoringModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerMonitoringModule {
+    public NetconfServerMonitoringModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetconfServerMonitoringModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.netconf.northbound.impl.NetconfServerMonitoringModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        return new NetconfMonitoringServiceImpl(getAggregatorDependency());
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerMonitoringModuleFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerMonitoringModuleFactory.java
new file mode 100644 (file)
index 0000000..fe74486
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-northbound-impl yang module local name: netconf-server-monitoring-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Tue Feb 17 17:24:19 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+public class NetconfServerMonitoringModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerMonitoringModuleFactory {
+
+}
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/CapabilityProviderImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/CapabilityProviderImpl.java
deleted file mode 100644 (file)
index 13cc973..0000000
+++ /dev/null
@@ -1,113 +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.impl;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class CapabilityProviderImpl implements CapabilityProvider {
-    private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
-    private final Set<String> capabilityURIs;
-
-    private static final Logger LOG = LoggerFactory.getLogger(CapabilityProviderImpl.class);
-
-    public CapabilityProviderImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
-        this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
-        Map<String, Capability> urisToCapabilitiesInternalMap = getCapabilitiesInternal(netconfOperationServiceSnapshot);
-        List<String> capabilityURIs = new ArrayList<>(urisToCapabilitiesInternalMap.keySet());
-        Collections.sort(capabilityURIs);
-        this.capabilityURIs = Collections.unmodifiableSet(new TreeSet<>(capabilityURIs));
-    }
-
-    private static Map<String, Capability> getCapabilitiesInternal(
-            NetconfOperationServiceSnapshot netconfOperationServiceSnapshot) {
-        Map<String, Capability> capabilityMap = Maps.newHashMap();
-
-        for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
-            final Set<Capability> caps = netconfOperationService.getCapabilities();
-
-            for (Capability cap : caps) {
-
-                if(capabilityMap.containsKey(cap.getCapabilityUri())) {
-                    LOG.debug("Duplicate capability {} from service {}", cap.getCapabilityUri(), netconfOperationService);
-                }
-
-                capabilityMap.put(cap.getCapabilityUri(), cap);
-            }
-        }
-
-        return capabilityMap;
-    }
-
-    @Override
-    public synchronized String getSchemaForCapability(String moduleName, Optional<String> revision) {
-
-        Map<String, Map<String, String>> mappedModulesToRevisionToSchema = Maps.newHashMap();
-
-        for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
-            final Set<Capability> caps = netconfOperationService.getCapabilities();
-
-            for (Capability cap : caps) {
-                if (!cap.getModuleName().isPresent()
-                        || !cap.getRevision().isPresent()
-                        || !cap.getCapabilitySchema().isPresent()){
-                    continue;
-                }
-
-                final String currentModuleName = cap.getModuleName().get();
-                Map<String, String> revisionMap = mappedModulesToRevisionToSchema.get(currentModuleName);
-                if (revisionMap == null) {
-                    revisionMap = Maps.newHashMap();
-                    mappedModulesToRevisionToSchema.put(currentModuleName, revisionMap);
-                }
-
-                String currentRevision = cap.getRevision().get();
-                revisionMap.put(currentRevision, cap.getCapabilitySchema().get());
-            }
-        }
-
-        Map<String, String> revisionMapRequest = mappedModulesToRevisionToSchema.get(moduleName);
-        Preconditions.checkState(revisionMapRequest != null, "Capability for module %s not present, " + ""
-                + "available modules : %s", moduleName, capabilityURIs);
-
-        if (revision.isPresent()) {
-            String schema = revisionMapRequest.get(revision.get());
-
-            Preconditions.checkState(schema != null,
-                    "Capability for module %s:%s not present, available revisions for module: %s", moduleName,
-                    revision.get(), revisionMapRequest.keySet());
-
-            return schema;
-        } else {
-            Preconditions.checkState(revisionMapRequest.size() == 1,
-                    "Expected 1 capability for module %s, available revisions : %s", moduleName,
-                    revisionMapRequest.keySet());
-            return revisionMapRequest.values().iterator().next();
-        }
-    }
-
-    @Override
-    public synchronized Set<String> getCapabilities() {
-        return capabilityURIs;
-    }
-
-}
index 8f2c39df063a813696735daa66d8e7831f9a756c..0cf2dbc281e1503e0ff1dd8d362285919c527c9a 100644 (file)
@@ -55,9 +55,9 @@ public final class NetconfServerSession extends AbstractNetconfSession<NetconfSe
 
     @Override
     protected void sessionUp() {
-        super.sessionUp();
         Preconditions.checkState(loginTime == null, "Session is already up");
         this.loginTime = new Date();
+        super.sessionUp();
     }
 
     public void onIncommingRpcSuccess() {
index 951d0dd98d7d2b52bb13e6fc21a8f88673c74de6..a6531d3c63d09b6fc64a1c0afd08e3f21041b2df 100644 (file)
@@ -15,10 +15,10 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
 import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -31,11 +31,11 @@ import org.w3c.dom.Node;
 public class NetconfServerSessionListener implements NetconfSessionListener<NetconfServerSession> {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfServerSessionListener.class);
-    private final SessionMonitoringService monitoringService;
+    private final NetconfMonitoringService monitoringService;
     private final NetconfOperationRouter operationRouter;
     private final AutoCloseable onSessionDownCloseable;
 
-    public NetconfServerSessionListener(final NetconfOperationRouter operationRouter, final SessionMonitoringService monitoringService,
+    public NetconfServerSessionListener(final NetconfOperationRouter operationRouter, NetconfMonitoringService monitoringService,
                                         final AutoCloseable onSessionDownCloseable) {
         this.operationRouter = operationRouter;
         this.monitoringService = monitoringService;
@@ -45,6 +45,8 @@ public class NetconfServerSessionListener implements NetconfSessionListener<Netc
     @Override
     public void onSessionUp(final NetconfServerSession netconfNetconfServerSession) {
         monitoringService.onSessionUp(netconfNetconfServerSession);
+        // FIXME monitoring service should be also notified about all the other changes to netconf session (from ietf-netconf-monitoring point of view)
+        // This means also notifying after every message is processed
     }
 
     @Override
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListenerFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListenerFactory.java
deleted file mode 100644 (file)
index 604cc5f..0000000
+++ /dev/null
@@ -1,41 +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.impl;
-
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
-import org.opendaylight.protocol.framework.SessionListenerFactory;
-
-public class NetconfServerSessionListenerFactory implements SessionListenerFactory<NetconfServerSessionListener> {
-
-    private final CommitNotifier commitNotifier;
-    private final SessionMonitoringService monitor;
-    private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
-    private final CapabilityProvider capabilityProvider;
-
-    public NetconfServerSessionListenerFactory(final CommitNotifier commitNotifier,
-                                               final SessionMonitoringService monitor,
-                                               final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
-                                               final CapabilityProvider capabilityProvider) {
-
-        this.commitNotifier = commitNotifier;
-        this.monitor = monitor;
-        this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
-        this.capabilityProvider = capabilityProvider;
-    }
-
-    @Override
-    public NetconfServerSessionListener getSessionListener() {
-        NetconfOperationRouter operationRouter = new NetconfOperationRouterImpl(netconfOperationServiceSnapshot, capabilityProvider, commitNotifier);
-        return new NetconfServerSessionListener(operationRouter, monitor, netconfOperationServiceSnapshot);
-    }
-}
index 451c066b772f5d705c0904fadd183ef48926a683..cf489608cab7c2a5ff36e2253c7fcc9516a296e4 100644 (file)
@@ -8,8 +8,6 @@
 
 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 com.google.common.collect.Sets;
@@ -19,11 +17,13 @@ import io.netty.util.concurrent.Promise;
 import java.util.Set;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.opendaylight.protocol.framework.SessionNegotiator;
@@ -42,28 +42,28 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     private final Timer timer;
 
     private final SessionIdProvider idProvider;
-    private final NetconfOperationProvider netconfOperationProvider;
+    private final NetconfOperationServiceFactory aggregatedOpService;
     private final long connectionTimeoutMillis;
     private final CommitNotifier commitNotificationProducer;
-    private final SessionMonitoringService monitoringService;
+    private final NetconfMonitoringService monitoringService;
     private static final Logger LOG = LoggerFactory.getLogger(NetconfServerSessionNegotiatorFactory.class);
     private final Set<String> baseCapabilities;
 
     // TODO too many params, refactor
-    public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
-                                                 SessionIdProvider idProvider, long connectionTimeoutMillis,
-                                                 CommitNotifier commitNot,
-                                                 SessionMonitoringService monitoringService) {
+    public NetconfServerSessionNegotiatorFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider,
+                                                 final SessionIdProvider idProvider, final long connectionTimeoutMillis,
+                                                 final CommitNotifier commitNot,
+                                                 final NetconfMonitoringService 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,
-                                                 CommitNotifier commitNot,
-                                                 SessionMonitoringService monitoringService, Set<String> baseCapabilities) {
+    public NetconfServerSessionNegotiatorFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider,
+                                                 final SessionIdProvider idProvider, final long connectionTimeoutMillis,
+                                                 final CommitNotifier commitNot,
+                                                 final NetconfMonitoringService monitoringService, final Set<String> baseCapabilities) {
         this.timer = timer;
-        this.netconfOperationProvider = netconfOperationProvider;
+        this.aggregatedOpService = netconfOperationProvider;
         this.idProvider = idProvider;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
         this.commitNotificationProducer = commitNot;
@@ -73,12 +73,12 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
 
     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);
+        final 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();
+        final 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);
@@ -95,32 +95,33 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
      * @return session negotiator
      */
     @Override
-    public SessionNegotiator<NetconfServerSession> getSessionNegotiator(SessionListenerFactory<NetconfServerSessionListener> defunctSessionListenerFactory,
-                                                                        Channel channel, Promise<NetconfServerSession> promise) {
-        long sessionId = idProvider.getNextSessionId();
-        NetconfOperationServiceSnapshot netconfOperationServiceSnapshot = netconfOperationProvider.openSnapshot(
-                getNetconfSessionIdForReporting(sessionId));
-        CapabilityProvider capabilityProvider = new CapabilityProviderImpl(netconfOperationServiceSnapshot);
-
-        NetconfServerSessionPreferences proposal = null;
+    public SessionNegotiator<NetconfServerSession> getSessionNegotiator(final SessionListenerFactory<NetconfServerSessionListener> defunctSessionListenerFactory,
+                                                                        final Channel channel, final Promise<NetconfServerSession> promise) {
+        final long sessionId = idProvider.getNextSessionId();
+
+        NetconfServerSessionPreferences proposal;
         try {
-            proposal = new NetconfServerSessionPreferences(
-                    createHelloMessage(sessionId, capabilityProvider), sessionId);
-        } catch (NetconfDocumentedException e) {
-            LOG.error("Unable to create hello mesage for session {} with capability provider {}", sessionId,capabilityProvider);
+            proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId, monitoringService), sessionId);
+        } catch (final NetconfDocumentedException e) {
+            LOG.error("Unable to create hello message for session {} with {}", sessionId, monitoringService);
             throw new IllegalStateException(e);
         }
 
-        NetconfServerSessionListenerFactory sessionListenerFactory = new NetconfServerSessionListenerFactory(
-                commitNotificationProducer, monitoringService,
-                netconfOperationServiceSnapshot, capabilityProvider);
-
         return new NetconfServerSessionNegotiator(proposal, promise, channel, timer,
-                sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
+                getListener(Long.toString(sessionId)), connectionTimeoutMillis);
+    }
+
+    private NetconfServerSessionListener getListener(final String netconfSessionIdForReporting) {
+        final NetconfOperationService service =
+                this.aggregatedOpService.createService(netconfSessionIdForReporting);
+        final NetconfOperationRouter operationRouter =
+                new NetconfOperationRouterImpl(service, commitNotificationProducer, monitoringService, netconfSessionIdForReporting);
+        return new NetconfServerSessionListener(operationRouter, monitoringService, service);
+
     }
 
-    private NetconfHelloMessage createHelloMessage(long sessionId, CapabilityProvider capabilityProvider) throws NetconfDocumentedException {
-        return NetconfHelloMessage.createServerHello(Sets.union(capabilityProvider.getCapabilities(), baseCapabilities), sessionId);
+    private NetconfHelloMessage createHelloMessage(final long sessionId, final NetconfMonitoringService capabilityProvider) throws NetconfDocumentedException {
+        return NetconfHelloMessage.createServerHello(Sets.union(DefaultCommit.transformCapabilities(capabilityProvider.getCapabilities()), baseCapabilities), sessionId);
     }
 
 }
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/CapabilityProvider.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/CapabilityProvider.java
deleted file mode 100644 (file)
index 60cde27..0000000
+++ /dev/null
@@ -1,20 +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.impl.mapping;
-
-import com.google.common.base.Optional;
-import java.util.Set;
-
-public interface CapabilityProvider {
-
-    String getSchemaForCapability(String moduleName, Optional<String> revision);
-
-    Set<String> getCapabilities();
-
-}
index 742255f973ca4eaebf79958e4c67d251e3a1b922..8b2c02bcd42cd916c2597b109762b686f68ea6c8 100644 (file)
@@ -8,18 +8,24 @@
 
 package org.opendaylight.controller.netconf.impl.mapping.operations;
 
+import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
 import java.io.InputStream;
+import java.util.Set;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.CommitNotifier;
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -32,10 +38,10 @@ public class DefaultCommit extends AbstractNetconfOperation {
     private static final String NOTIFY_ATTR = "notify";
 
     private final CommitNotifier notificationProducer;
-    private final CapabilityProvider cap;
+    private final NetconfMonitoringService cap;
     private final NetconfOperationRouter operationRouter;
 
-    public DefaultCommit(CommitNotifier notifier, CapabilityProvider cap,
+    public DefaultCommit(CommitNotifier notifier, NetconfMonitoringService cap,
                          String netconfSessionIdForReporting, NetconfOperationRouter netconfOperationRouter) {
         super(netconfSessionIdForReporting);
         this.notificationProducer = notifier;
@@ -73,12 +79,22 @@ public class DefaultCommit extends AbstractNetconfOperation {
             removePersisterAttributes(requestMessage);
             Element cfgSnapshot = getConfigSnapshot(operationRouter);
             LOG.debug("Config snapshot retrieved successfully {}", cfgSnapshot);
-            notificationProducer.sendCommitNotification("ok", cfgSnapshot, cap.getCapabilities());
+            notificationProducer.sendCommitNotification("ok", cfgSnapshot, transformCapabilities(cap.getCapabilities()));
         }
 
         return subsequentOperation.execute(requestMessage);
     }
 
+    // FIXME move somewhere to util since this is required also by negotiatiorFactory
+    public static Set<String> transformCapabilities(final Capabilities capabilities) {
+        return Sets.newHashSet(Collections2.transform(capabilities.getCapability(), new Function<Uri, String>() {
+            @Override
+            public String apply(final Uri uri) {
+                return uri.getValue();
+            }
+        }));
+    }
+
     @Override
     protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
         throw new UnsupportedOperationException("Never gets called");
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/AggregatedNetconfOperationServiceFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/AggregatedNetconfOperationServiceFactory.java
new file mode 100644 (file)
index 0000000..ae68ecc
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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.impl.osgi;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
+import org.opendaylight.controller.netconf.util.CloseableUtil;
+
+/**
+ * NetconfOperationService aggregator. Makes a collection of operation services accessible as one.
+ */
+public class AggregatedNetconfOperationServiceFactory implements NetconfOperationServiceFactory, NetconfOperationServiceFactoryListener, AutoCloseable {
+
+    private final Set<NetconfOperationServiceFactory> factories = new HashSet<>();
+    private final Multimap<NetconfOperationServiceFactory, AutoCloseable> registrations = HashMultimap.create();
+    private final Set<CapabilityListener> listeners = Sets.newHashSet();
+
+    @Override
+    public synchronized void onAddNetconfOperationServiceFactory(NetconfOperationServiceFactory service) {
+        factories.add(service);
+
+        for (final CapabilityListener listener : listeners) {
+            AutoCloseable reg = service.registerCapabilityListener(listener);
+            registrations.put(service, reg);
+        }
+    }
+
+    @Override
+    public synchronized void onRemoveNetconfOperationServiceFactory(NetconfOperationServiceFactory service) {
+        factories.remove(service);
+
+        for (final AutoCloseable autoCloseable : registrations.get(service)) {
+            try {
+                autoCloseable.close();
+            } catch (Exception e) {
+                // FIXME Issue warning
+            }
+        }
+
+        registrations.removeAll(service);
+    }
+
+    @Override
+    public synchronized Set<Capability> getCapabilities() {
+        final HashSet<Capability> capabilities = Sets.newHashSet();
+        for (final NetconfOperationServiceFactory factory : factories) {
+            capabilities.addAll(factory.getCapabilities());
+        }
+        return capabilities;
+    }
+
+    @Override
+    public synchronized AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+        final Map<NetconfOperationServiceFactory, AutoCloseable> regs = Maps.newHashMap();
+
+        for (final NetconfOperationServiceFactory factory : factories) {
+            final AutoCloseable reg = factory.registerCapabilityListener(listener);
+            regs.put(factory, reg);
+        }
+        listeners.add(listener);
+
+        return new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                synchronized (AggregatedNetconfOperationServiceFactory.this) {
+                    listeners.remove(listener);
+                    CloseableUtil.closeAll(regs.values());
+                    for (final Map.Entry<NetconfOperationServiceFactory, AutoCloseable> reg : regs.entrySet()) {
+                        registrations.remove(reg.getKey(), reg.getValue());
+                    }
+                }
+            }
+        };
+    }
+
+    @Override
+    public synchronized NetconfOperationService createService(final String netconfSessionIdForReporting) {
+        return new AggregatedNetconfOperation(factories, netconfSessionIdForReporting);
+    }
+
+    @Override
+    public synchronized void close() throws Exception {
+        factories.clear();
+        for (AutoCloseable reg : registrations.values()) {
+            reg.close();
+        }
+        registrations.clear();
+        listeners.clear();
+    }
+
+    private static final class AggregatedNetconfOperation implements NetconfOperationService {
+
+        private final Set<NetconfOperationService> services;
+
+        public AggregatedNetconfOperation(final Set<NetconfOperationServiceFactory> factories, final String netconfSessionIdForReporting) {
+            final Builder<NetconfOperationService> b = ImmutableSet.builder();
+            for (final NetconfOperationServiceFactory factory : factories) {
+                b.add(factory.createService(netconfSessionIdForReporting));
+            }
+            this.services = b.build();
+        }
+
+        @Override
+        public Set<NetconfOperation> getNetconfOperations() {
+            final HashSet<NetconfOperation> operations = Sets.newHashSet();
+            for (final NetconfOperationService service : services) {
+                operations.addAll(service.getNetconfOperations());
+            }
+            return operations;
+        }
+
+        @Override
+        public void close() {
+            try {
+                CloseableUtil.closeAll(services);
+            } catch (final Exception e) {
+                throw new IllegalStateException("Unable to properly close all aggregated services", e);
+            }
+        }
+    }
+}
index a55e32a954ad99a85521e11f541567c962a20b84..1e35597d9a6239d8566005b8bf3775b86282b082 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProduce
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -40,7 +40,7 @@ public class NetconfImplActivator implements BundleActivator {
     @Override
     public void start(final BundleContext context)  {
 
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+        AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
         startOperationServiceFactoryTracker(context, factoriesListener);
 
         SessionIdProvider idProvider = new SessionIdProvider();
@@ -50,7 +50,7 @@ public class NetconfImplActivator implements BundleActivator {
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
-        SessionMonitoringService monitoringService = startMonitoringService(context, factoriesListener);
+        NetconfMonitoringService monitoringService = startMonitoringService(context, factoriesListener);
 
         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
                 timer, factoriesListener, idProvider, connectionTimeoutMillis, commitNot, monitoringService);
@@ -64,17 +64,14 @@ public class NetconfImplActivator implements BundleActivator {
         LocalAddress address = NetconfConfigUtil.getNetconfLocalAddress();
         LOG.trace("Starting local netconf server at {}", address);
         dispatch.createLocalServer(address);
-
-        context.registerService(NetconfOperationProvider.class, factoriesListener, null);
-
     }
 
-    private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+    private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListener factoriesListener) {
         factoriesTracker = new NetconfOperationServiceFactoryTracker(context, factoriesListener);
         factoriesTracker.open();
     }
 
-    private NetconfMonitoringServiceImpl startMonitoringService(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+    private NetconfMonitoringServiceImpl startMonitoringService(BundleContext context, AggregatedNetconfOperationServiceFactory factoriesListener) {
         NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener);
         Dictionary<String, ?> dic = new Hashtable<>();
         regMonitoring = context.registerService(NetconfMonitoringService.class, netconfMonitoringServiceImpl, dic);
index efbe3ad68fe4615334c08206054cc755e20ff87b..b02137b748c71584841df04817a9f8bb552147e2 100644 (file)
@@ -8,25 +8,32 @@
 package org.opendaylight.controller.netconf.impl.osgi;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import io.netty.util.internal.ConcurrentSet;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import javax.annotation.Nonnull;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfStateBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
@@ -38,7 +45,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.mon
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, SessionMonitoringService {
+public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, AutoCloseable {
+
     private static final Schema.Location NETCONF_LOCATION = new Schema.Location(Schema.Location.Enumeration.NETCONF);
     private static final List<Schema.Location> NETCONF_LOCATIONS = ImmutableList.of(NETCONF_LOCATION);
     private static final Logger LOG = LoggerFactory.getLogger(NetconfMonitoringServiceImpl.class);
@@ -48,67 +56,142 @@ public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, S
             return input.toManagementSession();
         }
     };
+    private static final Function<Capability, Uri> CAPABILITY_TO_URI = new Function<Capability, Uri>() {
+        @Override
+        public Uri apply(final Capability input) {
+            return new Uri(input.getCapabilityUri());
+        }
+    };
 
     private final Set<NetconfManagementSession> sessions = new ConcurrentSet<>();
-    private final NetconfOperationProvider netconfOperationProvider;
+    private final NetconfOperationServiceFactory netconfOperationProvider;
+    private final Map<Uri, Capability> capabilities = new ConcurrentHashMap<>();
+
+    private final Set<MonitoringListener> listeners = Sets.newHashSet();
 
-    public NetconfMonitoringServiceImpl(final NetconfOperationProvider netconfOperationProvider) {
+    public NetconfMonitoringServiceImpl(final NetconfOperationServiceFactory netconfOperationProvider) {
         this.netconfOperationProvider = netconfOperationProvider;
+        netconfOperationProvider.registerCapabilityListener(this);
     }
 
     @Override
-    public void onSessionUp(final NetconfManagementSession session) {
+    public synchronized void onSessionUp(final NetconfManagementSession session) {
         LOG.debug("Session {} up", session);
         Preconditions.checkState(!sessions.contains(session), "Session %s was already added", session);
         sessions.add(session);
+        notifyListeners();
     }
 
     @Override
-    public void onSessionDown(final NetconfManagementSession session) {
+    public synchronized void onSessionDown(final NetconfManagementSession session) {
         LOG.debug("Session {} down", session);
         Preconditions.checkState(sessions.contains(session), "Session %s not present", session);
         sessions.remove(session);
+        notifyListeners();
     }
 
     @Override
-    public Sessions getSessions() {
+    public synchronized Sessions getSessions() {
         return new SessionsBuilder().setSession(ImmutableList.copyOf(Collections2.transform(sessions, SESSION_FUNCTION))).build();
     }
 
     @Override
-    public Schemas getSchemas() {
-        // capabilities should be split from operations (it will allow to move getSchema operation to monitoring module)
-        try (NetconfOperationServiceSnapshot snapshot = netconfOperationProvider.openSnapshot("netconf-monitoring")) {
-            return transformSchemas(snapshot.getServices());
-        } catch (RuntimeException e) {
+    public synchronized Schemas getSchemas() {
+        try {
+            return transformSchemas(netconfOperationProvider.getCapabilities());
+        } catch (final RuntimeException e) {
             throw e;
-        } catch (Exception e) {
+        } catch (final Exception e) {
             throw new IllegalStateException("Exception while closing", e);
         }
     }
 
-    private static Schemas transformSchemas(final Set<NetconfOperationService> services) {
-        // FIXME: Capability implementations do not have hashcode/equals!
-        final Set<Capability> caps = new HashSet<>();
-        for (NetconfOperationService netconfOperationService : services) {
-            // TODO check for duplicates ? move capability merging to snapshot
-            // Split capabilities from operations first and delete this duplicate code
-            caps.addAll(netconfOperationService.getCapabilities());
+    @Override
+    public synchronized String getSchemaForCapability(final String moduleName, final Optional<String> revision) {
+
+        // FIXME not effective at all
+
+        Map<String, Map<String, String>> mappedModulesToRevisionToSchema = Maps.newHashMap();
+
+        final Collection<Capability> caps = capabilities.values();
+
+        for (Capability cap : caps) {
+            if (!cap.getModuleName().isPresent()
+                    || !cap.getRevision().isPresent()
+                    || !cap.getCapabilitySchema().isPresent()){
+                continue;
+            }
+
+            final String currentModuleName = cap.getModuleName().get();
+            Map<String, String> revisionMap = mappedModulesToRevisionToSchema.get(currentModuleName);
+            if (revisionMap == null) {
+                revisionMap = Maps.newHashMap();
+                mappedModulesToRevisionToSchema.put(currentModuleName, revisionMap);
+            }
+
+            String currentRevision = cap.getRevision().get();
+            revisionMap.put(currentRevision, cap.getCapabilitySchema().get());
         }
 
+        Map<String, String> revisionMapRequest = mappedModulesToRevisionToSchema.get(moduleName);
+        Preconditions.checkState(revisionMapRequest != null, "Capability for module %s not present, " + ""
+                + "available modules : %s", moduleName, Collections2.transform(caps, CAPABILITY_TO_URI));
+
+        if (revision.isPresent()) {
+            String schema = revisionMapRequest.get(revision.get());
+
+            Preconditions.checkState(schema != null,
+                    "Capability for module %s:%s not present, available revisions for module: %s", moduleName,
+                    revision.get(), revisionMapRequest.keySet());
+
+            return schema;
+        } else {
+            Preconditions.checkState(revisionMapRequest.size() == 1,
+                    "Expected 1 capability for module %s, available revisions : %s", moduleName,
+                    revisionMapRequest.keySet());
+            return revisionMapRequest.values().iterator().next();
+        }
+    }
+
+    @Override
+    public synchronized Capabilities getCapabilities() {
+        return new CapabilitiesBuilder().setCapability(Lists.newArrayList(capabilities.keySet())).build();
+    }
+
+    @Override
+    public synchronized AutoCloseable registerListener(final MonitoringListener listener) {
+        listeners.add(listener);
+        listener.onStateChanged(getCurrentNetconfState());
+        return new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                listeners.remove(listener);
+            }
+        };
+    }
+
+    private NetconfState getCurrentNetconfState() {
+        return new NetconfStateBuilder()
+                .setCapabilities(getCapabilities())
+                .setSchemas(getSchemas())
+                .setSessions(getSessions())
+                .build();
+    }
+
+    private static Schemas transformSchemas(final Set<Capability> caps) {
         final List<Schema> schemas = new ArrayList<>(caps.size());
-        for (Capability cap : caps) {
+        for (final Capability cap : caps) {
             if (cap.getCapabilitySchema().isPresent()) {
-                SchemaBuilder builder = new SchemaBuilder();
+                final SchemaBuilder builder = new SchemaBuilder();
                 Preconditions.checkState(cap.getModuleNamespace().isPresent());
                 builder.setNamespace(new Uri(cap.getModuleNamespace().get()));
 
                 Preconditions.checkState(cap.getRevision().isPresent());
-                String version = cap.getRevision().get();
+                final String version = cap.getRevision().get();
                 builder.setVersion(version);
 
                 Preconditions.checkState(cap.getModuleName().isPresent());
-                String identifier = cap.getModuleName().get();
+                final String identifier = cap.getModuleName().get();
                 builder.setIdentifier(identifier);
 
                 builder.setFormat(Yang.class);
@@ -132,10 +215,38 @@ public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, S
         final Builder<Schema.Location> b = ImmutableList.builder();
         b.add(NETCONF_LOCATION);
 
-        for (String location : locations) {
+        for (final String location : locations) {
             b.add(new Schema.Location(new Uri(location)));
         }
 
         return b.build();
     }
+
+    @Override
+    public synchronized void onCapabilitiesAdded(final Set<Capability> addedCaps) {
+        // FIXME howto check for duplicates
+        this.capabilities.putAll(Maps.uniqueIndex(addedCaps, CAPABILITY_TO_URI));
+        notifyListeners();
+    }
+
+    private void notifyListeners() {
+        for (final MonitoringListener listener : listeners) {
+            listener.onStateChanged(getCurrentNetconfState());
+        }
+    }
+
+    @Override
+    public synchronized void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
+        for (final Capability addedCap : addedCaps) {
+            capabilities.remove(addedCap.getCapabilityUri());
+        }
+        notifyListeners();
+    }
+
+    @Override
+    public synchronized void close() throws Exception {
+        listeners.clear();
+        sessions.clear();
+        capabilities.clear();
+    }
 }
index c8fa3417473219cc284e5a7891726c52c58ad344..9d58bd911c828bfcba3b185b3db20dc9c0d87985 100644 (file)
@@ -17,12 +17,11 @@ import java.util.NavigableMap;
 import java.util.Set;
 import java.util.TreeMap;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.impl.CommitNotifier;
 import org.opendaylight.controller.netconf.impl.NetconfServerSession;
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
-import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultGetSchema;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultNetconfOperation;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStartExi;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStopExi;
@@ -30,7 +29,6 @@ import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
 import org.opendaylight.controller.netconf.mapping.api.SessionAwareNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
@@ -40,29 +38,20 @@ import org.w3c.dom.Document;
 public class NetconfOperationRouterImpl implements NetconfOperationRouter {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfOperationRouterImpl.class);
-    private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
+    private final NetconfOperationService netconfOperationServiceSnapshot;
     private final Collection<NetconfOperation> allNetconfOperations;
 
-    public NetconfOperationRouterImpl(final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot, final CapabilityProvider capabilityProvider,
-            final CommitNotifier commitNotifier) {
+    public NetconfOperationRouterImpl(final NetconfOperationService netconfOperationServiceSnapshot,
+                                      final CommitNotifier commitNotifier, final NetconfMonitoringService netconfMonitoringService, final String sessionId) {
         this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot);
 
-        final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting();
-
         final Set<NetconfOperation> ops = new HashSet<>();
-        ops.add(new DefaultGetSchema(capabilityProvider, sessionId));
         ops.add(new DefaultCloseSession(sessionId, this));
         ops.add(new DefaultStartExi(sessionId));
         ops.add(new DefaultStopExi(sessionId));
-        ops.add(new DefaultCommit(commitNotifier, capabilityProvider, sessionId, this));
+        ops.add(new DefaultCommit(commitNotifier, netconfMonitoringService, sessionId, this));
 
-        for (NetconfOperationService netconfOperationService : netconfOperationServiceSnapshot.getServices()) {
-            for (NetconfOperation netconfOperation : netconfOperationService.getNetconfOperations()) {
-                Preconditions.checkState(!ops.contains(netconfOperation),
-                        "Netconf operation %s already present", netconfOperation);
-                ops.add(netconfOperation);
-            }
-        }
+        ops.addAll(netconfOperationServiceSnapshot.getNetconfOperations());
 
         allNetconfOperations = ImmutableSet.copyOf(ops);
     }
@@ -154,8 +143,8 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
             if (!handlingPriority.equals(HandlingPriority.CANNOT_HANDLE)) {
 
                 Preconditions.checkState(!sortedPriority.containsKey(handlingPriority),
-                        "Multiple %s available to handle message %s with priority %s",
-                        NetconfOperation.class.getName(), message, handlingPriority);
+                        "Multiple %s available to handle message %s with priority %s, %s and %s",
+                        NetconfOperation.class.getName(), message, handlingPriority, netconfOperation, sortedPriority.get(handlingPriority));
                 sortedPriority.put(handlingPriority, netconfOperation);
             }
         }
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryListenerImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryListenerImpl.java
deleted file mode 100644 (file)
index 6c55c35..0000000
+++ /dev/null
@@ -1,34 +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.impl.osgi;
-
-import java.util.HashSet;
-import java.util.Set;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-
-public class NetconfOperationServiceFactoryListenerImpl implements NetconfOperationServiceFactoryListener,
-        NetconfOperationProvider {
-    private final Set<NetconfOperationServiceFactory> allFactories = new HashSet<>();
-
-    @Override
-    public synchronized void onAddNetconfOperationServiceFactory(NetconfOperationServiceFactory service) {
-        allFactories.add(service);
-    }
-
-    @Override
-    public synchronized void onRemoveNetconfOperationServiceFactory(NetconfOperationServiceFactory service) {
-        allFactories.remove(service);
-    }
-
-    @Override
-    public synchronized NetconfOperationServiceSnapshotImpl openSnapshot(String sessionIdForReporting) {
-        return new NetconfOperationServiceSnapshotImpl(allFactories, sessionIdForReporting);
-    }
-
-}
index 9a077a6130bb630cf9fdf5923e78a46eaaf6933b..d97ac909227fa937054ed18dd3ff159b29efedc3 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.netconf.impl.osgi;
 
 import org.opendaylight.controller.netconf.api.util.NetconfConstants;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.ServiceTracker;
@@ -40,8 +41,9 @@ class NetconfOperationServiceFactoryTracker extends
     @Override
     public void removedService(ServiceReference<NetconfOperationServiceFactory> reference,
             NetconfOperationServiceFactory netconfOperationServiceFactory) {
-        if (netconfOperationServiceFactory != null)
+        if (netconfOperationServiceFactory != null) {
             factoriesListener.onRemoveNetconfOperationServiceFactory(netconfOperationServiceFactory);
+        }
     }
 
 }
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshotImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshotImpl.java
deleted file mode 100644 (file)
index 26abdd9..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.impl.osgi;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSet.Builder;
-import java.util.Set;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
-import org.opendaylight.controller.netconf.util.CloseableUtil;
-
-public class NetconfOperationServiceSnapshotImpl implements NetconfOperationServiceSnapshot {
-
-    private final Set<NetconfOperationService> services;
-    private final String netconfSessionIdForReporting;
-
-    public NetconfOperationServiceSnapshotImpl(final Set<NetconfOperationServiceFactory> factories, final String sessionIdForReporting) {
-        final Builder<NetconfOperationService> b = ImmutableSet.builder();
-        netconfSessionIdForReporting = sessionIdForReporting;
-        for (NetconfOperationServiceFactory factory : factories) {
-            b.add(factory.createService(netconfSessionIdForReporting));
-        }
-        this.services = b.build();
-    }
-
-    @Override
-    public String getNetconfSessionIdForReporting() {
-        return netconfSessionIdForReporting;
-    }
-
-    @Override
-    public Set<NetconfOperationService> getServices() {
-        return services;
-    }
-
-    @Override
-    public void close() throws Exception {
-        CloseableUtil.closeAll(services);
-    }
-
-    @Override
-    public String toString() {
-        return "NetconfOperationServiceSnapshotImpl{" + netconfSessionIdForReporting + '}';
-    }
-}
index 6ca0a7781c815d08966397941080b1394d793863..7ad1fef55da1975e486012e690b8de0d929f3a15 100644 (file)
@@ -67,6 +67,15 @@ module netconf-northbound-impl {
                 }
             }
 
+            container server-monitor {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity nn:netconf-server-monitoring;
+                    }
+                }
+            }
+
             container timer {
                 uses config:service-ref {
                     refine type {
@@ -77,4 +86,43 @@ module netconf-northbound-impl {
         }
     }
 
+
+    identity netconf-server-monitoring-impl {
+            base config:module-type;
+            config:provided-service nn:netconf-server-monitoring;
+            config:java-name-prefix NetconfServerMonitoring;
+    }
+
+    // TODO Monitoring could expose the monitoring data over JMX...
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netconf-server-monitoring-impl {
+            when "/config:modules/config:module/config:type = 'netconf-server-monitoring-impl'";
+
+            container aggregator {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity nnm:netconf-northbound-mapper;
+                    }
+                }
+            }
+
+        }
+    }
+
+    identity netconf-mapper-aggregator {
+        base config:module-type;
+        config:provided-service nnm:netconf-northbound-mapper;
+        config:provided-service nnm:netconf-mapper-registry;
+        config:java-name-prefix NetconfMapperAggregator;
+        description "Aggregated operation provider for netconf servers. Joins all the operations and capabilities of all the mappers it aggregates and exposes them as a single service. The dependency orientation is reversed in order to prevent cyclic dependencies when monitoring service is considered";
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netconf-mapper-aggregator {
+            when "/config:modules/config:module/config:type = 'netconf-mapper-aggregator'";
+
+        }
+    }
+
 }
\ No newline at end of file
index 8e8a73b914cdf79ca7ad7e24d98ab31a859b0f44..512a127d224f80190757d85d98b5682e91e038a7 100644 (file)
@@ -12,7 +12,9 @@ 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.Matchers.anySetOf;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
 import com.google.common.base.Preconditions;
@@ -48,8 +50,11 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
@@ -57,9 +62,7 @@ import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionList
 import org.opendaylight.controller.netconf.client.TestingNetconfClient;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
@@ -71,6 +74,8 @@ 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.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -115,10 +120,19 @@ public class ConcurrentClientsTest {
     HashedWheelTimer hashedWheelTimer;
     private TestingNetconfOperation testingNetconfOperation;
 
-    public static SessionMonitoringService createMockedMonitoringService() {
-        SessionMonitoringService monitoring = mock(SessionMonitoringService.class);
+    public static NetconfMonitoringService createMockedMonitoringService() {
+        NetconfMonitoringService monitoring = mock(NetconfMonitoringService.class);
         doNothing().when(monitoring).onSessionUp(any(NetconfServerSession.class));
         doNothing().when(monitoring).onSessionDown(any(NetconfServerSession.class));
+        doReturn(new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+
+            }
+        }).when(monitoring).registerListener(any(NetconfMonitoringService.MonitoringListener.class));
+        doNothing().when(monitoring).onCapabilitiesAdded(anySetOf(Capability.class));
+        doNothing().when(monitoring).onCapabilitiesRemoved(anySetOf(Capability.class));
+        doReturn(new CapabilitiesBuilder().setCapability(Collections.<Uri>emptyList()).build()).when(monitoring).getCapabilities();
         return monitoring;
     }
 
@@ -143,7 +157,7 @@ public class ConcurrentClientsTest {
         nettyGroup = new NioEventLoopGroup(nettyThreads);
         netconfClientDispatcher = new NetconfClientDispatcherImpl(nettyGroup, nettyGroup, hashedWheelTimer);
 
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+        AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
 
         testingNetconfOperation = new TestingNetconfOperation();
         factoriesListener.onAddNetconfOperationServiceFactory(new TestingOperationServiceFactory(testingNetconfOperation));
@@ -259,13 +273,22 @@ public class ConcurrentClientsTest {
             this.operations = operations;
         }
 
+        @Override
+        public Set<Capability> getCapabilities() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+            return new AutoCloseable(){
+                @Override
+                public void close() throws Exception {}
+            };
+        }
+
         @Override
         public NetconfOperationService createService(String netconfSessionIdForReporting) {
             return new NetconfOperationService() {
-                @Override
-                public Set<Capability> getCapabilities() {
-                    return Collections.emptySet();
-                }
 
                 @Override
                 public Set<NetconfOperation> getNetconfOperations() {
index df4069ac17f1a37bb81833c067bc9d46488825bc..4fd04e29ef178148ced11c1e0fdd2e252703fd4a 100644 (file)
@@ -17,7 +17,7 @@ import java.net.InetSocketAddress;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
 
 public class NetconfDispatcherImplTest {
 
@@ -33,7 +33,7 @@ public class NetconfDispatcherImplTest {
 
         commitNot = new DefaultCommitNotificationProducer(
                 ManagementFactory.getPlatformMBeanServer());
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+        AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
 
         SessionIdProvider idProvider = new SessionIdProvider();
         hashedWheelTimer = new HashedWheelTimer();
index 93caa09286435f627638259784100d85ab203450..fed4742dd851d1a51a7e41a61e55355dc08a64d4 100644 (file)
@@ -8,107 +8,7 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import io.netty.channel.Channel;
-import java.util.Set;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
-import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-
 public class NetconfMonitoringServiceImplTest {
 
-    private NetconfMonitoringServiceImpl service;
-
-    @Mock
-    private NetconfOperationProvider operationProvider;
-    @Mock
-    private NetconfManagementSession managementSession;
-    @Mock
-    private NetconfOperationServiceSnapshot snapshot;
-    @Mock
-    private NetconfOperationService operationService;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        service = new NetconfMonitoringServiceImpl(operationProvider);
-    }
-
-    @Test
-    public void testSessions() throws Exception {
-        doReturn("sessToStr").when(managementSession).toString();
-        service.onSessionUp(managementSession);
-    }
-
-    @Test(expected = RuntimeException.class)
-    public void testGetSchemas() throws Exception {
-        doThrow(RuntimeException.class).when(operationProvider).openSnapshot(anyString());
-        service.getSchemas();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testGetSchemas2() throws Exception {
-        doThrow(Exception.class).when(operationProvider).openSnapshot(anyString());
-        service.getSchemas();
-    }
-
-    @Test
-    public void testGetSchemas3() throws Exception {
-        doReturn("").when(managementSession).toString();
-        Capability cap = mock(Capability.class);
-        Set<Capability> caps = Sets.newHashSet(cap);
-        Set<NetconfOperationService> services = Sets.newHashSet(operationService);
-        doReturn(snapshot).when(operationProvider).openSnapshot(anyString());
-        doReturn(services).when(snapshot).getServices();
-        doReturn(caps).when(operationService).getCapabilities();
-        Optional<String> opt = mock(Optional.class);
-        doReturn(opt).when(cap).getCapabilitySchema();
-        doReturn(true).when(opt).isPresent();
-        doReturn(opt).when(cap).getModuleNamespace();
-        doReturn("namespace").when(opt).get();
-        Optional<String> optRev = Optional.of("rev");
-        doReturn(optRev).when(cap).getRevision();
-        doReturn(Optional.of("modName")).when(cap).getModuleName();
-        doReturn(Lists.newArrayList("loc")).when(cap).getLocation();
-        doNothing().when(snapshot).close();
-
-        assertNotNull(service.getSchemas());
-        verify(snapshot, times(1)).close();
-
-        NetconfServerSessionListener sessionListener = mock(NetconfServerSessionListener.class);
-        Channel channel = mock(Channel.class);
-        doReturn("mockChannel").when(channel).toString();
-        NetconfHelloMessageAdditionalHeader header = new NetconfHelloMessageAdditionalHeader("name", "addr", "2", "tcp", "id");
-        NetconfServerSession sm = new NetconfServerSession(sessionListener, channel, 10, header);
-        doNothing().when(sessionListener).onSessionUp(any(NetconfServerSession.class));
-        sm.sessionUp();
-        service.onSessionUp(sm);
-        assertEquals(1, service.getSessions().getSession().size());
-
-        assertEquals(Long.valueOf(10), service.getSessions().getSession().get(0).getSessionId());
-
-        service.onSessionDown(sm);
-        assertEquals(0, service.getSessions().getSession().size());
-    }
+    // TODO redo test
 }
index 15aeb8d27c8badbafa64db0a7614174ce7155ceb..0c7406543fb7ba3456c20f71b8ae718c8fbbe04f 100644 (file)
@@ -18,17 +18,19 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import com.google.common.collect.Sets;
+import java.util.Collections;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerSession;
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -38,7 +40,7 @@ public class DefaultCommitTest {
     private Document requestMessage;
     private NetconfOperationRouter router;
     private DefaultCommitNotificationProducer notifier;
-    private CapabilityProvider cap;
+    private NetconfMonitoringService cap;
     private DefaultCommit commit;
 
     @Before
@@ -49,8 +51,8 @@ public class DefaultCommitTest {
         doReturn(false).when(operation).isExecutionTermination();
         notifier = mock(DefaultCommitNotificationProducer.class);
         doNothing().when(notifier).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
-        cap = mock(CapabilityProvider.class);
-        doReturn(Sets.newHashSet()).when(cap).getCapabilities();
+        cap = mock(NetconfMonitoringService.class);
+        doReturn(new CapabilitiesBuilder().setCapability(Collections.<Uri>emptyList()).build()).when(cap).getCapabilities();
         Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/editConfig_expectedResult.xml");
         doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class));
         commit = new DefaultCommit(notifier, cap, "", router);
index 413c9cc9452334640e3aab9269def616e99b1ff3..2fb989507c54f7f3aa065407a6664d554c7cd051 100644 (file)
@@ -12,7 +12,6 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import java.util.Arrays;
@@ -44,11 +43,11 @@ public class NetconfImplActivatorTest {
         doReturn(filter).when(bundle).createFilter(anyString());
         doNothing().when(bundle).addServiceListener(any(ServiceListener.class), anyString());
 
-        ServiceReference<?>[] refs = new ServiceReference[0];
+        ServiceReference<?>[] refs = {};
         doReturn(refs).when(bundle).getServiceReferences(anyString(), anyString());
         doReturn(Arrays.asList(refs)).when(bundle).getServiceReferences(any(Class.class), anyString());
         doReturn("").when(bundle).getProperty(anyString());
-        doReturn(registration).when(bundle).registerService(any(Class.class), any(NetconfOperationServiceFactoryListenerImpl.class), any(Dictionary.class));
+        doReturn(registration).when(bundle).registerService(any(Class.class), any(AggregatedNetconfOperationServiceFactory.class), any(Dictionary.class));
         doNothing().when(registration).unregister();
         doNothing().when(bundle).removeServiceListener(any(ServiceListener.class));
     }
@@ -57,7 +56,7 @@ public class NetconfImplActivatorTest {
     public void testStart() throws Exception {
         NetconfImplActivator activator = new NetconfImplActivator();
         activator.start(bundle);
-        verify(bundle, times(2)).registerService(any(Class.class), any(NetconfOperationServiceFactoryListenerImpl.class), any(Dictionary.class));
+        verify(bundle).registerService(any(Class.class), any(AggregatedNetconfOperationServiceFactory.class), any(Dictionary.class));
         activator.stop(bundle);
     }
 }
index 8cb569eaa283a974726ce3fab657f663fc72abb5..c75cdcd27a139db748db23d03c6fed5f8f767fc6 100644 (file)
@@ -22,6 +22,7 @@ import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.netconf.api.util.NetconfConstants;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Filter;
 import org.osgi.framework.ServiceReference;
index b70e97bac9289f15a3793473fb43cc026b6ce121..c2812dbf61af7241323941a9317780dd4e7df100 100644 (file)
@@ -13,7 +13,6 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anySetOf;
 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 io.netty.channel.Channel;
@@ -47,6 +46,7 @@ import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesMod
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
@@ -57,13 +57,11 @@ import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProduce
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
+import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
 import org.opendaylight.controller.netconf.notifications.BaseNetconfNotificationListener;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
@@ -108,14 +106,16 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
 
         setUpTestInitial();
 
-        final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+        final AggregatedNetconfOperationServiceFactory factoriesListener = new AggregatedNetconfOperationServiceFactory();
+        final NetconfMonitoringService netconfMonitoringService = getNetconfMonitoringService(factoriesListener);
         factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
+        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(new NetconfMonitoringOperationService(netconfMonitoringService)));
 
-        for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getAdditionalServiceFactories()) {
+        for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getAdditionalServiceFactories(factoriesListener)) {
             factoriesListener.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
         }
 
-        serverTcpChannel = startNetconfTcpServer(factoriesListener);
+        serverTcpChannel = startNetconfTcpServer(factoriesListener, netconfMonitoringService);
         clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
     }
 
@@ -137,8 +137,8 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
         return get;
     }
 
-    private Channel startNetconfTcpServer(final NetconfOperationServiceFactoryListenerImpl factoriesListener) throws Exception {
-        final NetconfServerDispatcherImpl dispatch = createDispatcher(factoriesListener, getNetconfMonitoringService(), getNotificationProducer());
+    private Channel startNetconfTcpServer(final AggregatedNetconfOperationServiceFactory listener, final NetconfMonitoringService monitoring) throws Exception {
+        final NetconfServerDispatcherImpl dispatch = createDispatcher(listener, monitoring, getNotificationProducer());
 
         final ChannelFuture s;
         if(getTcpServerAddress() instanceof LocalAddress) {
@@ -157,16 +157,12 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
         return notificationProducer;
     }
 
-    protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories() {
+    protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories(final AggregatedNetconfOperationServiceFactory factoriesListener) throws Exception {
         return Collections.emptySet();
     }
 
-    protected SessionMonitoringService getNetconfMonitoringService() throws Exception {
-        final NetconfOperationProvider netconfOperationProvider = mock(NetconfOperationProvider.class);
-        final NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
-        doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
-        doReturn(snap).when(netconfOperationProvider).openSnapshot(anyString());
-        return new NetconfMonitoringServiceImpl(netconfOperationProvider);
+    protected NetconfMonitoringService getNetconfMonitoringService(final AggregatedNetconfOperationServiceFactory factoriesListener) throws Exception {
+        return new NetconfMonitoringServiceImpl(factoriesListener);
     }
 
     protected abstract SocketAddress getTcpServerAddress();
@@ -206,7 +202,7 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
     }
 
     protected NetconfServerDispatcherImpl createDispatcher(
-            final NetconfOperationServiceFactoryListenerImpl factoriesListener, final SessionMonitoringService sessionMonitoringService,
+            final AggregatedNetconfOperationServiceFactory factoriesListener, final NetconfMonitoringService sessionMonitoringService,
             final DefaultCommitNotificationProducer commitNotifier) {
         final SessionIdProvider idProvider = new SessionIdProvider();
 
index 92c96d92f28962eeb88ccc961665d852cd39364c..c421a46fdf1662405b18390e81df1c6945a660fe 100644 (file)
@@ -9,23 +9,18 @@ package org.opendaylight.controller.netconf.it;
 
 import static org.junit.Assert.assertEquals;
 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 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 com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
-import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 import javax.management.InstanceNotFoundException;
 import javax.management.Notification;
 import javax.management.NotificationListener;
@@ -38,15 +33,6 @@ import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
 import org.opendaylight.controller.netconf.client.TestingNetconfClient;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
-import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.w3c.dom.Document;
@@ -58,29 +44,12 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
     public static final int PORT = 12026;
     private static final InetSocketAddress TCP_ADDRESS = new InetSocketAddress(LOOPBACK_ADDRESS, PORT);
 
-    private NetconfMonitoringServiceImpl netconfMonitoringService;
-
-    @Override
-    protected void setUpTestInitial() {
-        netconfMonitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
-    }
-
-    @Override
-    protected SessionMonitoringService getNetconfMonitoringService() throws Exception {
-        return netconfMonitoringService;
-    }
 
     @Override
     protected SocketAddress getTcpServerAddress() {
         return TCP_ADDRESS;
     }
 
-    @Override
-    protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories() {
-        return Collections.<NetconfOperationServiceFactory>singletonList(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
-                new NetconfMonitoringOperationService(netconfMonitoringService)));
-    }
-
     @Override
     protected DefaultCommitNotificationProducer getNotificationProducer() {
         return new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
@@ -95,7 +64,6 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
             try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(
                     platformMBeanServer, mockedAggregator)) {
 
-
                 try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 4000))) {
                     NetconfMessage response = netconfClient.sendMessage(loadGetConfigMessage());
                     assertContainsElementWithName(response.getDocument(), "modules");
@@ -112,8 +80,8 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
         }
 
         notificationVerifier.assertNotificationCount(2);
-        notificationVerifier.assertNotificationContent(0, 0, 0, 9);
-        notificationVerifier.assertNotificationContent(1, 4, 3, 9);
+        notificationVerifier.assertNotificationContent(0, 0, 0, 8);
+        notificationVerifier.assertNotificationContent(1, 4, 3, 8);
 
         mockedAggregator.assertSnapshotCount(2);
         // Capabilities are stripped for persister
@@ -143,20 +111,6 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
         return XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml");
     }
 
-
-    public NetconfOperationProvider getNetconfOperationProvider() {
-        final NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
-        final NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
-        final NetconfOperationService service = mock(NetconfOperationService.class);
-        final Set<Capability> caps = Sets.newHashSet();
-        doReturn(caps).when(service).getCapabilities();
-        final Set<NetconfOperationService> services = Sets.newHashSet(service);
-        doReturn(services).when(snap).getServices();
-        doReturn(snap).when(factoriesListener).openSnapshot(anyString());
-
-        return factoriesListener;
-    }
-
     private static class VerifyingNotificationListener implements NotificationListener {
         public List<Notification> notifications = Lists.newArrayList();
 
index ea94fd3f8bbf9d5c56f697877b88905e89740335..e745b393fbcb271868e0f9e2c68366a6b44f38c1 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.netconf.it;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -26,21 +27,14 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import org.junit.Test;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.client.TestingNetconfClient;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
-import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
 import org.w3c.dom.Document;
 
 public class NetconfITMonitoringTest extends AbstractNetconfConfigTest {
@@ -49,45 +43,11 @@ public class NetconfITMonitoringTest extends AbstractNetconfConfigTest {
     public static final InetSocketAddress TCP_ADDRESS = new InetSocketAddress(LOOPBACK_ADDRESS, PORT);
     public static final TestingCapability TESTING_CAPABILITY = new TestingCapability();
 
-    private NetconfMonitoringServiceImpl netconfMonitoringService;
-
-    @Override
-    protected void setUpTestInitial() {
-        netconfMonitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
-    }
-
-    @Override
-    protected SessionMonitoringService getNetconfMonitoringService() throws Exception {
-        return netconfMonitoringService;
-    }
-
-    @Override
-    protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories() {
-        return Collections.<NetconfOperationServiceFactory>singletonList(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
-                new NetconfMonitoringOperationService(netconfMonitoringService)));
-    }
-
     @Override
     protected InetSocketAddress getTcpServerAddress() {
         return TCP_ADDRESS;
     }
 
-    static SessionMonitoringService getNetconfMonitoringListenerService(final Logger LOG, final NetconfMonitoringServiceImpl monitor) {
-        return new SessionMonitoringService() {
-            @Override
-            public void onSessionUp(final NetconfManagementSession session) {
-                LOG.debug("Management session up {}", session);
-                monitor.onSessionUp(session);
-            }
-
-            @Override
-            public void onSessionDown(final NetconfManagementSession session) {
-                LOG.debug("Management session down {}", session);
-                monitor.onSessionDown(session);
-            }
-        };
-    }
-
     @Test
     public void testGetResponseFromMonitoring() throws Exception {
         try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 10000))) {
@@ -151,23 +111,24 @@ public class NetconfITMonitoringTest extends AbstractNetconfConfigTest {
         assertEquals("Incorrect number of session-id tags in " + XmlUtil.toString(document), i, elementSize);
     }
 
-    public static NetconfOperationProvider getNetconfOperationProvider() {
-        final NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
-        final NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
+    public static AggregatedNetconfOperationServiceFactory getNetconfOperationProvider() throws Exception {
+        final AggregatedNetconfOperationServiceFactory factoriesListener = mock(AggregatedNetconfOperationServiceFactory.class);
+        final NetconfOperationService snap = mock(NetconfOperationService.class);
         try {
             doNothing().when(snap).close();
         } catch (final Exception e) {
             // not happening
             throw new IllegalStateException(e);
         }
-        final NetconfOperationService service = mock(NetconfOperationService.class);
         final Set<Capability> caps = Sets.newHashSet();
         caps.add(TESTING_CAPABILITY);
 
-        doReturn(caps).when(service).getCapabilities();
-        final Set<NetconfOperationService> services = Sets.newHashSet(service);
-        doReturn(services).when(snap).getServices();
-        doReturn(snap).when(factoriesListener).openSnapshot(anyString());
+        doReturn(caps).when(factoriesListener).getCapabilities();
+        doReturn(snap).when(factoriesListener).createService(anyString());
+
+        AutoCloseable mock = mock(AutoCloseable.class);
+        doNothing().when(mock).close();
+        doReturn(mock).when(factoriesListener).registerCapabilityListener(any(CapabilityListener.class));
 
         return factoriesListener;
     }
diff --git a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationProvider.java b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationProvider.java
deleted file mode 100644 (file)
index f5c50f8..0000000
+++ /dev/null
@@ -1,23 +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.mapping.api;
-
-public interface NetconfOperationProvider {
-
-    NetconfOperationServiceSnapshot openSnapshot(String sessionIdForReporting);
-
-    public static class NetconfOperationProviderUtil {
-
-        public static String getNetconfSessionIdForReporting(long sessionId) {
-            return "netconf session id " + sessionId;
-        }
-
-    }
-
-}
index 5e2cba2cbaeea86985a9bf33fedbb2c30ee78ebf..1a1a124895f240f1a85cfefd78c4172c04391b65 100644 (file)
@@ -15,11 +15,6 @@ import java.util.Set;
  */
 public interface NetconfOperationService extends AutoCloseable {
 
-    /**
-     * Get capabilities announced by server hello message.
-     */
-    Set<Capability> getCapabilities();
-
     /**
      * Get set of netconf operations that are handled by this service.
      */
index 81401f26eecc4796a61f2740b079a7351e33007a..8caa177bfa525dd87ce38a1e914d1920dc1dc1be 100644 (file)
@@ -8,6 +8,10 @@
 
 package org.opendaylight.controller.netconf.mapping.api;
 
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+
 /**
  * Factory that must be registered in OSGi service registry in order to be used
  * by netconf-impl. Responsible for creating per-session instances of
@@ -15,6 +19,16 @@ package org.opendaylight.controller.netconf.mapping.api;
  */
 public interface NetconfOperationServiceFactory {
 
+    /**
+     * Get capabilities supported by current operation service.
+     */
+    Set<Capability> getCapabilities();
+
+    /**
+     * Supported capabilities may change over time, registering a listener allows for push based information retrieval about current notifications
+     */
+    AutoCloseable registerCapabilityListener(CapabilityListener listener);
+
     NetconfOperationService createService(String netconfSessionIdForReporting);
 
 }
diff --git a/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceSnapshot.java b/opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceSnapshot.java
deleted file mode 100644 (file)
index eaa6937..0000000
+++ /dev/null
@@ -1,18 +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.mapping.api;
-
-import java.util.Set;
-
-public interface NetconfOperationServiceSnapshot extends AutoCloseable {
-    String getNetconfSessionIdForReporting();
-
-    Set<NetconfOperationService> getServices();
-
-}
index a709665c63a1e2293a70c2b4d4f118fdd863750a..3ffecde700e894dd144d935eab4d806e061aadde 100644 (file)
@@ -19,4 +19,9 @@ module netconf-northbound-mapper {
         config:java-class "org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory";
     }
 
+    identity netconf-mapper-registry {
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener";
+    }
+
 }
\ No newline at end of file
index 042447b1e65cca2d20d28664f4c690e22baefc1f..4ca3c99e813c0711865a3ef704f60e52014c8c93 100644 (file)
                   <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
                   <name>inmemory-data-broker</name>
               </dom-broker>
+              <mapper-aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-mapper-registry</type>
+                  <name>mapper-aggregator-registry</name>
+              </mapper-aggregator>
           </module>
 
           <module>
               <name>netconf-mdsal-server-dispatcher</name>
               <mappers xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
                   <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">dom:netconf-northbound-mapper</type>
-                  <name>netconf-mdsal-mapper</name>
+                  <name>mapper-aggregator</name>
               </mappers>
+              <server-monitor xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-monitoring</type>
+                  <name>server-monitor</name>
+              </server-monitor>
               <boss-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
                   <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
                   <name>global-boss-group</name>
               </timer>
           </module>
 
+          <module>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">prefix:netconf-mdsal-monitoring-mapper</type>
+              <name>netconf-mdsal-monitoring-mapper</name>
+              <server-monitoring xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-monitoring</type>
+                  <name>server-monitor</name>
+              </server-monitoring>
+              <binding-aware-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-broker-osgi-registry</type>
+                  <name>binding-osgi-broker</name>
+              </binding-aware-broker>
+              <aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-mapper-registry</type>
+                  <name>mapper-aggregator-registry</name>
+              </aggregator>
+          </module>
+
+          <module>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">prefix:netconf-mapper-aggregator</type>
+              <name>mapper-aggregator</name>
+          </module>
+
+          <module>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">prefix:netconf-server-monitoring-impl</type>
+              <name>server-monitor</name>
+              <aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+                  <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">dom:netconf-northbound-mapper</type>
+                  <name>mapper-aggregator</name>
+              </aggregator>
+          </module>
+
           <module>
               <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">prefix:netconf-northbound-ssh</type>
               <name>netconf-mdsal-ssh-server</name>
       </modules>
 
         <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+            <service>
+                <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-monitoring</type>
+                <instance>
+                    <name>server-monitor</name>
+                    <provider>/modules/module[type='netconf-server-monitoring-impl'][name='server-monitor']</provider>
+                </instance>
+            </service>
             <service>
                 <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-northbound-mapper</type>
                 <instance>
                     <provider>/modules/module[type='netconf-mdsal-mapper'][name='netconf-mdsal-mapper']</provider>
                 </instance>
             </service>
+            <service>
+                <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-northbound-mapper</type>
+                <instance>
+                    <name>mapper-aggregator</name>
+                    <provider>/modules/module[type='netconf-mapper-aggregator'][name='mapper-aggregator']</provider>
+                </instance>
+            </service>
+            <service>
+                <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-mapper-registry</type>
+                <instance>
+                    <name>mapper-aggregator-registry</name>
+                    <provider>/modules/module[type='netconf-mapper-aggregator'][name='mapper-aggregator']</provider>
+                </instance>
+            </service>
             <service>
                 <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-dispatcher</type>
                 <instance>
   </configuration>
   <required-capabilities>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper?module=netconf-mdsal-mapper&amp;revision=2015-01-14</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring?module=netconf-mdsal-monitoring&amp;revision=2015-02-18</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh?module=netconf-northbound-ssh&amp;revision=2015-01-14</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl?module=netconf-northbound-impl&amp;revision=2015-01-12</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled?module=threadpool-impl-scheduled&amp;revision=2013-12-01</capability>
@@ -1,19 +1,19 @@
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2015 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.impl.mapping.operations;
+package org.opendaylight.controller.netconf.monitoring;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.Maps;
 import java.util.Map;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
@@ -23,16 +23,16 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-public final class DefaultGetSchema extends AbstractLastNetconfOperation {
+public class GetSchema extends AbstractLastNetconfOperation {
     public static final String GET_SCHEMA = "get-schema";
     public static final String IDENTIFIER = "identifier";
     public static final String VERSION = "version";
 
-    private static final Logger LOG = LoggerFactory.getLogger(DefaultGetSchema.class);
-    private final CapabilityProvider cap;
+    private static final Logger LOG = LoggerFactory.getLogger(GetSchema.class);
+    private final NetconfMonitoringService cap;
 
-    public DefaultGetSchema(CapabilityProvider cap, String netconfSessionIdForReporting) {
-        super(netconfSessionIdForReporting);
+    public GetSchema(final NetconfMonitoringService cap) {
+        super(MonitoringConstants.MODULE_NAME);
         this.cap = cap;
     }
 
@@ -47,16 +47,16 @@ public final class DefaultGetSchema extends AbstractLastNetconfOperation {
     }
 
     @Override
-    protected Element handleWithNoSubsequentOperations(Document document, XmlElement xml) throws NetconfDocumentedException {
-        GetSchemaEntry entry;
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement xml) throws NetconfDocumentedException {
+        final GetSchemaEntry entry;
 
         entry = new GetSchemaEntry(xml);
 
-        String schema;
+        final String schema;
         try {
             schema = cap.getSchemaForCapability(entry.identifier, entry.version);
-        } catch (IllegalStateException e) {
-            Map<String, String> errorInfo = Maps.newHashMap();
+        } catch (final IllegalStateException e) {
+            final Map<String, String> errorInfo = Maps.newHashMap();
             errorInfo.put(entry.identifier, e.getMessage());
             LOG.warn("Rpc error: {}", NetconfDocumentedException.ErrorTag.operation_failed, e);
             throw new NetconfDocumentedException(e.getMessage(), NetconfDocumentedException.ErrorType.application,
@@ -64,7 +64,7 @@ public final class DefaultGetSchema extends AbstractLastNetconfOperation {
                     NetconfDocumentedException.ErrorSeverity.error, errorInfo);
         }
 
-        Element getSchemaResult;
+        final Element getSchemaResult;
         getSchemaResult = XmlUtil.createTextElement(document, XmlNetconfConstants.DATA_KEY, schema,
                 Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING));
         LOG.trace("{} operation successful", GET_SCHEMA);
@@ -76,19 +76,19 @@ public final class DefaultGetSchema extends AbstractLastNetconfOperation {
         private final String identifier;
         private final Optional<String> version;
 
-        GetSchemaEntry(XmlElement getSchemaElement) throws NetconfDocumentedException {
+        GetSchemaEntry(final XmlElement getSchemaElement) throws NetconfDocumentedException {
             getSchemaElement.checkName(GET_SCHEMA);
             getSchemaElement.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING);
 
             XmlElement identifierElement = null;
             try {
                 identifierElement = getSchemaElement.getOnlyChildElementWithSameNamespace(IDENTIFIER);
-            } catch (MissingNameSpaceException e) {
+            } catch (final MissingNameSpaceException e) {
                 LOG.trace("Can't get identifier element as only child element with same namespace due to ",e);
                 throw NetconfDocumentedException.wrap(e);
             }
             identifier = identifierElement.getTextContent();
-            Optional<XmlElement> versionElement = getSchemaElement
+            final Optional<XmlElement> versionElement = getSchemaElement
                     .getOnlyChildElementWithSameNamespaceOptionally(VERSION);
             if (versionElement.isPresent()) {
                 version = Optional.of(versionElement.get().getTextContent());
index 1411350cd3dce0fec1d4854e3eeabe580c4aef4d..1f094f1caf3d8f57c7301a9a42cf6f0ea2c5d922 100644 (file)
@@ -7,6 +7,10 @@
 */
 package org.opendaylight.controller.netconf.monitoring.osgi;
 
+import java.util.Collections;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.osgi.framework.BundleActivator;
@@ -31,22 +35,43 @@ public class NetconfMonitoringActivator implements BundleActivator {
         if(monitor!=null) {
             try {
                 monitor.close();
-            } catch (Exception e) {
+            } catch (final Exception e) {
                 LOG.warn("Ignoring exception while closing {}", monitor, e);
             }
         }
     }
 
-    public static class NetconfMonitoringOperationServiceFactory implements NetconfOperationServiceFactory {
+    public static class NetconfMonitoringOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable {
+
         private final NetconfMonitoringOperationService operationService;
 
-        public NetconfMonitoringOperationServiceFactory(NetconfMonitoringOperationService operationService) {
+        private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                // NOOP
+            }
+        };
+
+        public NetconfMonitoringOperationServiceFactory(final NetconfMonitoringOperationService operationService) {
             this.operationService = operationService;
         }
 
         @Override
-        public NetconfOperationService createService(String netconfSessionIdForReporting) {
+        public NetconfOperationService createService(final String netconfSessionIdForReporting) {
             return operationService;
         }
+
+        @Override
+        public Set<Capability> getCapabilities() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+            return AUTO_CLOSEABLE;
+        }
+
+        @Override
+        public void close() {}
     }
 }
index a17e139131461bcc2c7ac12505f9d59ae207eba0..efe71e912739d9b5988b18bc6ecdf73a498f9424 100644 (file)
@@ -7,67 +7,25 @@
 */
 package org.opendaylight.controller.netconf.monitoring.osgi;
 
-import com.google.common.base.Optional;
 import com.google.common.collect.Sets;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.Set;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.monitoring.Get;
-import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+import org.opendaylight.controller.netconf.monitoring.GetSchema;
 
 public class NetconfMonitoringOperationService implements NetconfOperationService {
 
-    private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
-
-        @Override
-        public String getCapabilityUri() {
-            return MonitoringConstants.URI;
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.of(MonitoringConstants.NAMESPACE);
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.of(MonitoringConstants.MODULE_NAME);
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.of(MonitoringConstants.MODULE_REVISION);
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Collection<String> getLocation() {
-            return Collections.emptyList();
-        }
-    });
-
     private final NetconfMonitoringService monitor;
 
     public NetconfMonitoringOperationService(final NetconfMonitoringService monitor) {
         this.monitor = monitor;
     }
 
-    @Override
-    public Set<Capability> getCapabilities() {
-        return CAPABILITIES;
-    }
-
     @Override
     public Set<NetconfOperation> getNetconfOperations() {
-        return Sets.<NetconfOperation>newHashSet(new Get(monitor));
+        return Sets.<NetconfOperation>newHashSet(new Get(monitor), new GetSchema(monitor));
     }
 
     @Override
index 9e7c105aa4e0cf53f95ebeb290b181866e54cc8a..5d0a2a91ad59f95ea20df53b7bc62433479f4650 100644 (file)
@@ -25,6 +25,7 @@ public class NetconfMonitoringServiceTracker extends ServiceTracker<NetconfMonit
     private static final Logger LOG = LoggerFactory.getLogger(NetconfMonitoringServiceTracker.class);
 
     private ServiceRegistration<NetconfOperationServiceFactory> reg;
+    private NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory factory;
 
     NetconfMonitoringServiceTracker(final BundleContext context) {
         super(context, NetconfMonitoringService.class, null);
@@ -38,7 +39,7 @@ public class NetconfMonitoringServiceTracker extends ServiceTracker<NetconfMonit
 
         final NetconfMonitoringOperationService operationService = new NetconfMonitoringOperationService(
                 netconfMonitoringService);
-        final NetconfOperationServiceFactory factory = new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
+        factory = new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
                 operationService);
 
         Dictionary<String, String> properties = new Hashtable<>();
@@ -58,6 +59,9 @@ public class NetconfMonitoringServiceTracker extends ServiceTracker<NetconfMonit
                 LOG.warn("Ignoring exception while unregistering {}", reg, e);
             }
         }
+        if(factory!=null) {
+            factory.close();
+        }
     }
 
 }
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2015 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.impl.mapping.operations;
+package org.opendaylight.controller.netconf.monitoring;
 
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Matchers.any;
@@ -19,20 +19,21 @@ import com.google.common.base.Optional;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 
-public class DefaultGetSchemaTest {
+public class GetSchemaTest {
 
-    private CapabilityProvider cap;
+
+    private NetconfMonitoringService cap;
     private Document doc;
     private String getSchema;
 
     @Before
     public void setUp() throws Exception {
-        cap = mock(CapabilityProvider.class);
+        cap = mock(NetconfMonitoringService.class);
         doc = XmlUtil.newDocument();
         getSchema = "<get-schema xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
                 "        <identifier>threadpool-api</identifier>\n" +
@@ -45,15 +46,16 @@ public class DefaultGetSchemaTest {
 
     @Test(expected = NetconfDocumentedException.class)
     public void testDefaultGetSchema() throws Exception {
-        DefaultGetSchema schema = new DefaultGetSchema(cap, "");
+        GetSchema schema = new GetSchema(cap);
         doThrow(IllegalStateException.class).when(cap).getSchemaForCapability(anyString(), any(Optional.class));
         schema.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement(getSchema)));
     }
 
     @Test
     public void handleWithNoSubsequentOperations() throws Exception {
-        DefaultGetSchema schema = new DefaultGetSchema(cap, "");
+        GetSchema schema = new GetSchema(cap);
         doReturn("").when(cap).getSchemaForCapability(anyString(), any(Optional.class));
         assertNotNull(schema.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement(getSchema))));
     }
-}
+
+}
\ No newline at end of file
index 7873183188bb36c56ae93d8fce996bc18b504d6f..67a54366cdcb9f189aabc89d31753e0232d6b7aa 100644 (file)
@@ -11,25 +11,17 @@ package org.opendaylight.controller.netconf.monitoring.osgi;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
-import com.google.common.base.Optional;
-import java.util.Collections;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
 
 public class NetconfMonitoringOperationServiceTest {
     @Test
     public void testGetters() throws Exception {
         NetconfMonitoringService monitor = mock(NetconfMonitoringService.class);
         NetconfMonitoringOperationService service = new NetconfMonitoringOperationService(monitor);
+        NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory serviceFactory = new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(service);
 
-        assertEquals(1, service.getNetconfOperations().size());
+        assertEquals(2, service.getNetconfOperations().size());
 
-        assertEquals(Optional.<String>absent(), service.getCapabilities().iterator().next().getCapabilitySchema());
-        assertEquals(Collections.<String>emptyList(), service.getCapabilities().iterator().next().getLocation());
-        assertEquals(Optional.of(MonitoringConstants.MODULE_REVISION), service.getCapabilities().iterator().next().getRevision());
-        assertEquals(Optional.of(MonitoringConstants.MODULE_NAME), service.getCapabilities().iterator().next().getModuleName());
-        assertEquals(Optional.of(MonitoringConstants.NAMESPACE), service.getCapabilities().iterator().next().getModuleNamespace());
-        assertEquals(MonitoringConstants.URI, service.getCapabilities().iterator().next().getCapabilityUri());
     }
 }
index 4b5dcd7d5578941523d0b76eb6f88aa97c353b13..a8236b2ebc38017a64af7a2ad1619a9a129d1f3e 100644 (file)
@@ -11,9 +11,13 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
+import java.util.Set;
 import org.hamcrest.CoreMatchers;
 import org.junit.Test;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -25,6 +29,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.mon
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
@@ -42,6 +47,26 @@ public class JaxBSerializerTest {
 
         final NetconfMonitoringService service = new NetconfMonitoringService() {
 
+            @Override
+            public void onSessionUp(final NetconfManagementSession session) {
+
+            }
+
+            @Override
+            public void onSessionDown(final NetconfManagementSession session) {
+
+            }
+
+            @Override
+            public void onCapabilitiesAdded(final Set<Capability> addedCaps) {
+
+            }
+
+            @Override
+            public void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
+
+            }
+
             @Override
             public Sessions getSessions() {
                 return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession(NetconfTcp.class), getMockSession(NetconfSsh.class))).build();
@@ -51,6 +76,26 @@ public class JaxBSerializerTest {
             public Schemas getSchemas() {
                 return new SchemasBuilder().setSchema(Lists.newArrayList(getMockSchema("id", "v1", Yang.class), getMockSchema("id2", "", Yang.class))).build();
             }
+
+            @Override
+            public String getSchemaForCapability(final String moduleName, final Optional<String> revision) {
+                return null;
+            }
+
+            @Override
+            public Capabilities getCapabilities() {
+                return null;
+            }
+
+            @Override
+            public AutoCloseable registerListener(final MonitoringListener listener) {
+                return new AutoCloseable() {
+                    @Override
+                    public void close() throws Exception {
+                        // NOOP
+                    }
+                };
+            }
         };
         final NetconfState model = new NetconfState(service);
         final String xml = XmlUtil.toString(new JaxBSerializer().toXml(model)).replaceAll("\\s", "");
index 9eab5caff74fe3411d0ccaa847594d1834e574ea..a0a0dfcb8f5e506071daa1b5b894aa0074f556ca 100644 (file)
@@ -15,8 +15,9 @@ import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.api.util.NetconfConstants;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
@@ -42,16 +43,30 @@ public class Activator implements BundleActivator {
 
         final NetconfOperationServiceFactory netconfOperationServiceFactory = new NetconfOperationServiceFactory() {
 
+            private final Set<Capability> capabilities = Collections.<Capability>singleton(new NotificationsCapability());
+
+            @Override
+            public Set<Capability> getCapabilities() {
+                return capabilities;
+            }
+
+            @Override
+            public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+                listener.onCapabilitiesAdded(capabilities);
+                return new AutoCloseable() {
+                    @Override
+                    public void close() {
+                        listener.onCapabilitiesRemoved(capabilities);
+                    }
+                };
+            }
+
             @Override
             public NetconfOperationService createService(final String netconfSessionIdForReporting) {
                 return new NetconfOperationService() {
 
                     private final CreateSubscription createSubscription = new CreateSubscription(netconfSessionIdForReporting, netconfNotificationManager);
 
-                    @Override
-                    public Set<Capability> getCapabilities() {
-                        return Collections.<Capability>singleton(new NotificationsCapability());
-                    }
 
                     @Override
                     public Set<NetconfOperation> getNetconfOperations() {
@@ -68,7 +83,7 @@ public class Activator implements BundleActivator {
             }
         };
 
-        Dictionary<String, String> properties = new Hashtable<>();
+        final Dictionary<String, String> properties = new Hashtable<>();
         properties.put(NetconfConstants.SERVICE_NAME, NetconfConstants.NETCONF_MONITORING);
         operationaServiceRegistration = context.registerService(NetconfOperationServiceFactory.class, netconfOperationServiceFactory, properties);
 
index fcb513f0165265fbf09d5ab68df8693e07c3753f..3aba6f81a3bc04770c21d5725efe90b582113594 100644 (file)
@@ -12,8 +12,8 @@ import com.google.common.base.Optional;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
 
index 68f8796d819f301b20f0d17e274fc0b981cb9816..11af568321cf59cba2cf62077787f19fb8e266e9 100644 (file)
@@ -12,8 +12,8 @@ import com.google.common.base.Optional;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
 
index 30b307658964c59706818fff40846a135387cb28..bb67af2032793fdac1a8038377c8550b5f045d50 100644 (file)
@@ -55,19 +55,20 @@ import org.apache.sshd.common.util.ThreadUtils;
 import org.apache.sshd.server.PasswordAuthenticator;
 import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
 import org.apache.sshd.server.session.ServerSession;
-import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
 import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
 import org.opendaylight.controller.netconf.ssh.SshProxyServer;
 import org.opendaylight.controller.netconf.ssh.SshProxyServerConfiguration;
@@ -141,9 +142,15 @@ public class NetconfDeviceSimulator implements Closeable {
 
         final SessionIdProvider idProvider = new SessionIdProvider();
 
+
+        final AggregatedNetconfOperationServiceFactory aggregatedNetconfOperationServiceFactory = new AggregatedNetconfOperationServiceFactory();
         final SimulatedOperationProvider simulatedOperationProvider = new SimulatedOperationProvider(idProvider, capabilities, notificationsFile);
-        final NetconfMonitoringOperationService monitoringService = new NetconfMonitoringOperationService(new NetconfMonitoringServiceImpl(simulatedOperationProvider));
-        simulatedOperationProvider.addService(monitoringService);
+
+        final NetconfMonitoringService monitoringService1 = new NetconfMonitoringServiceImpl(aggregatedNetconfOperationServiceFactory);
+        final NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory monitoringService =
+                new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(new NetconfMonitoringOperationService(monitoringService1));
+        aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(simulatedOperationProvider);
+        aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(monitoringService);
 
         final DefaultCommitNotificationProducer commitNotifier = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
@@ -152,7 +159,7 @@ public class NetconfDeviceSimulator implements Closeable {
                 : Sets.newHashSet(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0, XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1);
 
         final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                hashedWheelTimer, simulatedOperationProvider, idProvider, generateConfigsTimeout, commitNotifier, new LoggingMonitoringService(), serverCapabilities);
+                hashedWheelTimer, aggregatedNetconfOperationServiceFactory, idProvider, generateConfigsTimeout, commitNotifier, monitoringService1, serverCapabilities);
 
         final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
                 serverNegotiatorFactory);
@@ -396,65 +403,43 @@ public class NetconfDeviceSimulator implements Closeable {
         // close Everything
     }
 
-    private static class SimulatedOperationProvider implements NetconfOperationProvider {
-        private final SessionIdProvider idProvider;
-        private final Set<NetconfOperationService> netconfOperationServices;
+    private static class SimulatedOperationProvider implements NetconfOperationServiceFactory {
+        private final Set<Capability> caps;
+        private final SimulatedOperationService simulatedOperationService;
 
 
         public SimulatedOperationProvider(final SessionIdProvider idProvider, final Set<Capability> caps, final Optional<File> notificationsFile) {
-            this.idProvider = idProvider;
-            final SimulatedOperationService simulatedOperationService = new SimulatedOperationService(caps, idProvider.getCurrentSessionId(), notificationsFile);
-            this.netconfOperationServices = Sets.<NetconfOperationService>newHashSet(simulatedOperationService);
+            this.caps = caps;
+            simulatedOperationService = new SimulatedOperationService(idProvider.getCurrentSessionId(), notificationsFile);
         }
 
         @Override
-        public NetconfOperationServiceSnapshot openSnapshot(final String sessionIdForReporting) {
-            return new SimulatedServiceSnapshot(idProvider, netconfOperationServices);
+        public Set<Capability> getCapabilities() {
+            return caps;
         }
 
-        public void addService(final NetconfOperationService monitoringService) {
-            netconfOperationServices.add(monitoringService);
+        @Override
+        public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+            return new AutoCloseable() {
+                @Override
+                public void close() throws Exception {}
+            };
         }
 
-        private static class SimulatedServiceSnapshot implements NetconfOperationServiceSnapshot {
-            private final SessionIdProvider idProvider;
-            private final Set<NetconfOperationService> netconfOperationServices;
-
-            public SimulatedServiceSnapshot(final SessionIdProvider idProvider, final Set<NetconfOperationService> netconfOperationServices) {
-                this.idProvider = idProvider;
-                this.netconfOperationServices = netconfOperationServices;
-            }
-
-            @Override
-            public String getNetconfSessionIdForReporting() {
-                return String.valueOf(idProvider.getCurrentSessionId());
-            }
-
-            @Override
-            public Set<NetconfOperationService> getServices() {
-                return netconfOperationServices;
-            }
-
-            @Override
-            public void close() throws Exception {}
+        @Override
+        public NetconfOperationService createService(final String netconfSessionIdForReporting) {
+            return simulatedOperationService;
         }
 
         static class SimulatedOperationService implements NetconfOperationService {
-            private final Set<Capability> capabilities;
             private final long currentSessionId;
             private final Optional<File> notificationsFile;
 
-            public SimulatedOperationService(final Set<Capability> capabilities, final long currentSessionId, final Optional<File> notificationsFile) {
-                this.capabilities = capabilities;
+            public SimulatedOperationService(final long currentSessionId, final Optional<File> notificationsFile) {
                 this.currentSessionId = currentSessionId;
                 this.notificationsFile = notificationsFile;
             }
 
-            @Override
-            public Set<Capability> getCapabilities() {
-                return capabilities;
-            }
-
             @Override
             public Set<NetconfOperation> getNetconfOperations() {
                 final DataList storage = new DataList();
@@ -475,16 +460,4 @@ public class NetconfDeviceSimulator implements Closeable {
         }
     }
 
-    private class LoggingMonitoringService implements SessionMonitoringService {
-        @Override
-        public void onSessionUp(final NetconfManagementSession session) {
-            LOG.debug("Session {} established", session);
-        }
-
-        @Override
-        public void onSessionDown(final NetconfManagementSession session) {
-            LOG.debug("Session {} down", session);
-        }
-    }
-
 }
index 4566845e4f88fe7b3c1ee23e12b6ef41a5e6a653..a990b5c6cb935d1139f54353a5282329f9fd3b0e 100644 (file)
@@ -21,6 +21,7 @@
     <module>netconf-impl</module>
     <module>config-netconf-connector</module>
     <module>mdsal-netconf-connector</module>
+    <module>mdsal-netconf-monitoring</module>
     <module>netconf-util</module>
     <module>netconf-netty-util</module>
     <module>config-persister-impl</module>