Merge "Fix for Bug 2727 - Upgrade Akka from 2.3.4 to 2.3.9"
authorTom Pantelis <tpanteli@brocade.com>
Sat, 21 Feb 2015 13:36:49 +0000 (13:36 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 21 Feb 2015 13:36:50 +0000 (13:36 +0000)
171 files changed:
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
opendaylight/commons/opendaylight/pom.xml
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/NeverReconnectStrategyFactoryModule.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/NeverReconnectStrategyFactoryModuleFactory.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModule.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModuleFactory.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModule.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModuleFactory.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractProtocolSession.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/NeverReconnectStrategy.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolSession.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolSessionPromise.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectImmediatelyStrategy.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectPromise.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectStrategy.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectStrategyFactory.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionListener.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionListenerFactory.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionNegotiator.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/SessionNegotiatorFactory.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/TerminationReason.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/TimedReconnectStrategy.java
opendaylight/md-sal/mdsal-artifacts/pom.xml
opendaylight/md-sal/messagebus-api/pom.xml [new file with mode: 0644]
opendaylight/md-sal/messagebus-api/src/main/yang/event-aggregator.yang [new file with mode: 0644]
opendaylight/md-sal/messagebus-api/src/main/yang/event-source.yang [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/pom.xml [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/config/yang/messagebus/app/impl/MessageBusAppImplModule.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/config/yang/messagebus/app/impl/MessageBusAppImplModuleFactory.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/DataStore.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/InitializationContext.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/MdSAL.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/Providers.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventAggregator.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventSourceManager.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventSourceTopology.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/NetconfEventSource.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/Topic.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/Util.java [new file with mode: 0644]
opendaylight/md-sal/messagebus-impl/src/main/yang/messagebus-app-impl.yang [new file with mode: 0644]
opendaylight/md-sal/pom.xml
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/ReplicatedLog.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/base/messages/CaptureSnapshot.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/AbstractRaftActorBehavior.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.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/behaviors/RaftActorBehavior.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/messages/AppendEntries.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/messages/AppendEntriesReply.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/main/java/org/opendaylight/controller/cluster/raft/messages/InstallSnapshotReply.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/messages/RequestVote.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/messages/RequestVoteReply.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImplTest.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/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/MessageCollectorActor.java
opendaylight/md-sal/sal-akka-raft/src/test/resources/simplelogger.properties
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-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActor.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/Shard.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.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/ShardTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcIdentifier.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementationUnavailableException.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/PingPongTransaction.java
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 [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/AbstractDOMStoreTransaction.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.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/osgi/Activator.java
opendaylight/netconf/mdsal-netconf-connector/pom.xml [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModuleFactory.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/CurrentSchemaContext.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/OperationProvider.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/TransactionProvider.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Commit.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Datastore.java [moved from opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/InitiateInstallSnapshot.java with 51% similarity]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/DiscardChanges.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Lock.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Unlock.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/Get.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/GetConfig.java [new file with mode: 0644]
opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang [new file with mode: 0644]
opendaylight/netconf/netconf-api/pom.xml
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfServerDispatcher.java [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/util/NetconfConstants.java [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/yang/netconf-northbound.yang [new file with mode: 0644]
opendaylight/netconf/netconf-artifacts/pom.xml
opendaylight/netconf/netconf-config/src/main/resources/initial/01-netconf.xml
opendaylight/netconf/netconf-connector-config/src/main/resources/initial/99-netconf-connector.xml
opendaylight/netconf/netconf-impl/pom.xml
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerDispatcherModule.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerDispatcherModuleFactory.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/CommitNotifier.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/DefaultCommitNotificationProducer.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcherImpl.java [moved from opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java with 86% similarity]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListenerFactory.java
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/operations/DefaultCommit.java
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/NetconfOperationRouterImpl.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTracker.java
opendaylight/netconf/netconf-impl/src/main/yang/netconf-northbound-impl.yang [new file with mode: 0644]
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/osgi/NetconfOperationServiceFactoryTrackerTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java
opendaylight/netconf/netconf-mapping-api/pom.xml
opendaylight/netconf/netconf-mapping-api/src/main/yang/netconf-northbound-mapper.yang [new file with mode: 0644]
opendaylight/netconf/netconf-mdsal-config/pom.xml [new file with mode: 0644]
opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTracker.java
opendaylight/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/controller/netconf/notifications/impl/osgi/Activator.java
opendaylight/netconf/netconf-ssh/pom.xml
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/config/yang/netconf/northbound/ssh/NetconfNorthboundSshModule.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/config/yang/netconf/northbound/ssh/NetconfNorthboundSshModuleFactory.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/yang/netconf-northbound-ssh.yang [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java
opendaylight/netconf/pom.xml

index 5e6afd248f261ec5642ebd87592569bdec059054..c63b39c74d50df358e2393624a4de99eb97bf839 100644 (file)
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-netconf</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>features-config-persister</artifactId>
index 8c166e63821fe2197211c72b8f195db8813f9202..5b9f4a674a733a7850a40b83622b34b43b1e9fff 100644 (file)
@@ -7,6 +7,7 @@
     <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.controller/features-config-persister/${config.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.controller/features-config-netty/${config.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-netconf/${netconf.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.controller/features-akka/${commons.opendaylight.version}/xml/features</repository>
     <feature name='odl-mdsal-all' version='${project.version}' description="OpenDaylight :: MDSAL :: All">
         <feature version='${project.version}'>odl-mdsal-broker</feature>
       <bundle>mvn:org.opendaylight.controller/sal-common-impl/${mdsal.version}</bundle>
       <bundle>mvn:org.opendaylight.controller/sal-common-util/${mdsal.version}</bundle>
     </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">
+        <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>
+        <!-- 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>
+        <configfile finalname='${config.configfile.directory}/${config.netconf.mdsal.configfile}'>mvn:org.opendaylight.controller/netconf-mdsal-config/${netconf.version}/xml/config</configfile>
+    </feature>
+
     <feature name='odl-mdsal-broker' version='${project.version}' description="OpenDaylight :: MDSAL :: Broker">
         <feature version='${yangtools.version}'>odl-yangtools-common</feature>
         <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
index c69ee197be24dfa8db753ff96a99e13d37e186c3..4e94996634716590376611354356a7085e4e3d38 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>
index 863833bcc0493105536a0af9fcb4926b26cf66a1..92e6507d2178a5a17997be74d6bb59b4d9006ee9 100644 (file)
@@ -42,6 +42,8 @@
         -->
         <feature version='${project.version}'>odl-netconf-connector</feature>
         <feature version='${project.version}'>odl-netconf-connector-ssh</feature>
+
+
     </feature>
     <!--
         Necessary TODO: Define your features.  It is useful to list then in order of dependency.  So if A depends on B, list A first.
index 997b6a275f6e1803bba685b136a4af686212d785..4edd93629408d1e1fec37e96b879976ec0f23677 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-mdsal-config</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-auth</artifactId>
index fd62fc7b143c6285f0662276b29205628fd348ca..338db8b03a04e0db32be91b42abea3f752cad48c 100644 (file)
@@ -61,6 +61,7 @@
     <config.xsql.configfile>04-xsql.xml</config.xsql.configfile>
     <config.netconf.client.configfile>01-netconf.xml</config.netconf.client.configfile>
     <config.toaster.configfile>03-toaster-sample.xml</config.toaster.configfile>
+    <config.netconf.mdsal.configfile>08-mdsal-netconf.xml</config.netconf.mdsal.configfile>
     <config.restconf.configfile>10-rest-connector.xml</config.restconf.configfile>
     <config.netconf.connector.configfile>99-netconf-connector.xml</config.netconf.connector.configfile>
     <configuration.implementation.version>0.5.0-SNAPSHOT</configuration.implementation.version>
index a97f65e941c890df21f1bf595fd755d59f8e7659..31e7a24feec44ed63581e41e09ad9d711f7338a2 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
 /**
 *
 */
+@Deprecated
 public final class NeverReconnectStrategyFactoryModule extends org.opendaylight.controller.config.yang.protocol.framework.AbstractNeverReconnectStrategyFactoryModule
  {
 
index 7f5233c827c2624befc01adb1b9c02a5da30c606..7b8816bd1b38843f2b0440c2bc565beaa13144fa 100644 (file)
@@ -39,6 +39,7 @@ import io.netty.util.concurrent.Promise;
  * Dispatcher class for creating servers and clients. The idea is to first create servers and clients and the run the
  * start method that will handle sockets in different thread.
  */
+@Deprecated
 public abstract class AbstractDispatcher<S extends ProtocolSession<?>, L extends SessionListener<?, ?, ?>> implements Closeable {
 
 
index af196a941a777df18eacc9d2929a3048e57677ab..44afc4e7a1f18c52b61916a8e3948343122956c1 100644 (file)
@@ -13,6 +13,7 @@ import io.netty.channel.SimpleChannelInboundHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Deprecated
 public abstract class AbstractProtocolSession<M> extends SimpleChannelInboundHandler<Object> implements ProtocolSession<M> {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractProtocolSession.class);
 
index 2ecd267b9f47b195b406b4ed0d8c8fd3b068937a..8a19828c578d21b5a29b0c6ca14ddbea5831b889 100644 (file)
@@ -27,6 +27,7 @@ import com.google.common.base.Preconditions;
  * @param <M> Protocol message type
  * @param <S> Protocol session type, has to extend ProtocolSession<M>
  */
+@Deprecated
 public abstract class AbstractSessionNegotiator<M, S extends AbstractProtocolSession<?>> extends ChannelInboundHandlerAdapter implements SessionNegotiator<S> {
     private final Logger LOG = LoggerFactory.getLogger(AbstractSessionNegotiator.class);
     private final Promise<S> promise;
index c4802944178ba37d8636924c73cd51c383a6871c..926183f973ed43ec722a8350b846d83d4a1024f6 100644 (file)
@@ -18,6 +18,7 @@ import com.google.common.base.Preconditions;
  * Utility ReconnectStrategy singleton, which will cause the reconnect process
  * to always fail.
  */
+@Deprecated
 @ThreadSafe
 public final class NeverReconnectStrategy implements ReconnectStrategy {
     private final EventExecutor executor;
index 6e79d6765dce0ff50ff10c168440469331690b2a..b99844112f7789b918f337a88390ba03ef984f1f 100644 (file)
@@ -17,6 +17,7 @@ import java.io.Closeable;
  *
  * This interface should be implemented by a final class representing a protocol specific session.
  */
+@Deprecated
 public interface ProtocolSession<T> extends Closeable {
     @Override
     void close();
index a38db61eaddcdb4ebd2daa79f03790fc6bde2007..b64c4828a4a7315524afc3370a6bca95c8711b29 100644 (file)
@@ -23,6 +23,7 @@ import javax.annotation.concurrent.ThreadSafe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Deprecated
 @ThreadSafe
 final class ProtocolSessionPromise<S extends ProtocolSession<?>> extends DefaultPromise<S> {
     private static final Logger LOG = LoggerFactory.getLogger(ProtocolSessionPromise.class);
index a567af1f762aac9016b9ccfefc2a54f239f44b6c..56cdcfb0c35b09e673984d7846d379395a1e0c1a 100644 (file)
@@ -21,6 +21,7 @@ import com.google.common.base.Preconditions;
  * Utility ReconnectStrategy singleton, which will cause the reconnect process
  * to immediately schedule a reconnection attempt.
  */
+@Deprecated
 @ThreadSafe
 public final class ReconnectImmediatelyStrategy implements ReconnectStrategy {
     private static final Logger LOG = LoggerFactory.getLogger(ReconnectImmediatelyStrategy.class);
index 865c666ad299ccbf86e260ed9f477d052763695f..e57976449bef78f2c6422420233f2d60e79fd0cd 100644 (file)
@@ -21,6 +21,7 @@ import java.net.InetSocketAddress;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Deprecated
 final class ReconnectPromise<S extends ProtocolSession<?>, L extends SessionListener<?, ?, ?>> extends DefaultPromise<Void> {
     private static final Logger LOG = LoggerFactory.getLogger(ReconnectPromise.class);
 
index 24ff84b6ab3466a8815d1afb4a4bf972480c7495..a0a91507997fa34bc5518de9cf18a5266e59d818 100644 (file)
@@ -23,6 +23,7 @@ import io.netty.util.concurrent.Future;
  * not attempt any more connection attempts and should abort the reconnection
  * process.
  */
+@Deprecated
 public interface ReconnectStrategy {
     /**
      * Query the strategy for the connect timeout.
index 3c61044beeeaf4714c8a5caf45eb8477c063697c..a71fa677c82539b2426452d8cda827d4d80084d8 100644 (file)
@@ -12,6 +12,7 @@ package org.opendaylight.protocol.framework;
  * primarily useful for allowing injection of a specific type of strategy for
  * on-demand use, pretty much like you would use a ThreadFactory.
  */
+@Deprecated
 public interface ReconnectStrategyFactory {
     /**
      * Create a new ReconnectStrategy.
index a756a0da7e780e84510d8e329b475b9342e0c9e7..dfe0208c54b33156892843bf961c0e0ad6aafd6c 100644 (file)
@@ -14,6 +14,7 @@ import java.util.EventListener;
  * implemented by a protocol specific abstract class, that is extended by
  * a final class that implements the methods.
  */
+@Deprecated
 public interface SessionListener<M, S extends ProtocolSession<?>, T extends TerminationReason> extends EventListener {
     /**
      * Fired when the session was established successfully.
index 11871286cf7f01e2f386487d1137f8d228bd1b0b..99087a5434538461f28887866c4fe2bf0c30a6f1 100644 (file)
@@ -13,6 +13,7 @@ package org.opendaylight.protocol.framework;
  * implemented by a protocol specific abstract class, that is extended by
  * a final class that implements the methods.
  */
+@Deprecated
 public interface SessionListenerFactory<T extends SessionListener<?, ?, ?>> {
     /**
      * Returns one session listener
index 3de64b07ff589f49a0428b55288d7a34c9628040..c2abf50716648b87405c338cf809dfb8a31c55fb 100644 (file)
@@ -17,6 +17,7 @@ import io.netty.channel.ChannelInboundHandler;
  *
  * @param <T> Protocol session type.
  */
+@Deprecated
 public interface SessionNegotiator<T extends ProtocolSession<?>> extends ChannelInboundHandler {
 
 }
index 90844ca712a1d012b15f390618fd68f19dcd238d..66293f368fa66f2a46cfdcd03b806c7ab9df7328 100644 (file)
@@ -15,6 +15,7 @@ import io.netty.util.concurrent.Promise;
  *
  * @param <S> session type
  */
+@Deprecated
 public interface SessionNegotiatorFactory<M, S extends ProtocolSession<?>, L extends SessionListener<?, ?, ?>> {
     /**
      * Create a new negotiator attached to a channel, which will notify
index 1a6179dc3548175a2b6287f2af1d021a6391d668..19d11125e5b86aa42df55aa9189cceddd396756d 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.protocol.framework;
 /**
  * Marker interface for grouping session termination cause.
  */
+@Deprecated
 public interface TerminationReason {
 
     /**
index 8bb326821dcd98d4e2a300b2ce595d07824e55e4..ecb9e65a528a104f0e7727f45e65f97d9e583c44 100644 (file)
@@ -42,6 +42,7 @@ import com.google.common.base.Preconditions;
  *
  * Both these caps can be combined, with the strategy giving up as soon as the first one is reached.
  */
+@Deprecated
 @ThreadSafe
 public final class TimedReconnectStrategy implements ReconnectStrategy {
     private static final Logger LOG = LoggerFactory.getLogger(TimedReconnectStrategy.class);
index f88e09cecba5b456e73b9ce25e6fc09efa74bc7c..420f888cf179740f309f9a6ace29912344ca0fe9 100644 (file)
                 <type>xml</type>
             </dependency>
 
+            <!-- MessageBus -->
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>message-bus-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>message-bus-impl</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 </project>
diff --git a/opendaylight/md-sal/messagebus-api/pom.xml b/opendaylight/md-sal/messagebus-api/pom.xml
new file mode 100644 (file)
index 0000000..542308a
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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
+-->
+<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>sal-parent</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>message-bus-api</artifactId>
+    <name>${project.artifactId}</name>
+
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-inventory</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>yang-ext</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-topology</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>${project.build.directory}/generated-sources/sal</outputBaseDir>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                                    <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>target/site/models</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.build.directory}/generated-sources/config</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.*</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/opendaylight/md-sal/messagebus-api/src/main/yang/event-aggregator.yang b/opendaylight/md-sal/messagebus-api/src/main/yang/event-aggregator.yang
new file mode 100644 (file)
index 0000000..ad7b573
--- /dev/null
@@ -0,0 +1,131 @@
+module event-aggregator {
+    // FIXME: this module needs to be split up to concepts and API
+    //        as the concepts are shared with the other model in this
+    //        package.
+    yang-version 1;
+    namespace "urn:cisco:params:xml:ns:yang:messagebus:eventaggregator";
+    prefix "eventaggregator";
+
+    organization "Cisco Systems, Inc.";
+    contact "Robert Gallas";
+
+    description
+        "Module implementing message but RPC.
+
+        Copyright (c)2014 Cisco Systems, Inc. All rights reserved.
+
+        This program and the accompanying materials are made available
+        under the terms of the Eclipse Public License v1.0 which
+        accompanies this distribution, and is available at
+        http://www.eclipse.org/legal/epl-v10.html";
+
+    revision "2014-12-02" {
+        description "Initial revision";
+    }
+
+    typedef pattern {
+        type string {
+            length 1..max;
+        }
+
+        // FIXME: make this a regular expression
+        description "A match pattern. Specifically this is a wildcard pattern.";
+    }
+
+    typedef notification-pattern {
+        type pattern;
+        description
+            "Pattern for matching candidate notification types. This pattern is to be
+            applied against the concatenation of the namespace of the module which
+            defines that particular notification, followed by a single colon, and
+            then followed by notification identifier, as supplied in the argument to
+            the notification statement.";
+    }
+
+    typedef topic-id {
+        type string {
+            length 1..max;
+        }
+        description
+            "A topic identifier. It uniquely defines a topic as seen by the the user
+            of this model's RPCs";
+    }
+
+    // FIXME: we would really like to share instances here, but that requires some sort
+    //        of sane reference counting. The reason for sharing is the data path part
+    //        of notification delivery -- multiple creators of topics can still share
+    //        a single data path.
+    rpc create-topic {
+        description
+            "Create a new topic. A topic is an aggregation of several notification
+            types from a set of nodes. Each successful invocation results in a unique
+            topic being created. The caller is responsible for removing the topic
+            once it is no longer needed.";
+
+        input {
+            leaf notification-pattern {
+                type notification-pattern;
+                mandatory true;
+                description
+                    "Pattern matching notification which should be forwarded into this
+                    topic.";
+            }
+
+            leaf node-id-pattern {
+                type pattern;
+                mandatory true;
+                description
+                    "Pattern for matching candidate event source nodes when looking
+                    for contributors to the topic. The pattern will be applied against
+                    /network-topology/topology/node/node-id";
+            }
+        }
+
+        output {
+            leaf topic-id {
+                type topic-id;
+                mandatory true;
+            }
+        }
+    }
+
+    rpc destroy-topic {
+        description
+            "Destroy a topic. No further messages will be delivered to it.";
+
+        input {
+            leaf topic-id {
+                type topic-id;
+                mandatory true;
+            }
+        }
+    }
+
+    notification topic-notification {
+        description
+            "Notification of an event occuring on a particular node. This notification
+            acts as an encapsulation for the event being delivered.";
+
+        leaf topic-id {
+            type topic-id;
+            mandatory true;
+            description
+                "Topic to which this event is being delivered.";
+        }
+
+        leaf node-id {
+            // FIXME: should be topology node ID
+            type string;
+            mandatory true;
+            description
+                "Node ID of the node which generated the event.";
+        }
+
+        anyxml payload {
+            mandatory true;
+            description
+                "Encapsulated notification. The format is the XML representation of
+                a notification according to RFC6020 section 7.14.2.";
+        }
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-api/src/main/yang/event-source.yang b/opendaylight/md-sal/messagebus-api/src/main/yang/event-source.yang
new file mode 100644 (file)
index 0000000..5dd416c
--- /dev/null
@@ -0,0 +1,85 @@
+module event-source {
+    yang-version 1;
+    namespace "urn:cisco:params:xml:ns:yang:messagebus:eventsource";
+    prefix "eventsource";
+
+    import event-aggregator { prefix aggr; }
+    import network-topology { prefix nt; revision-date "2013-10-21"; }
+    import opendaylight-inventory {prefix inv; revision-date "2013-08-19"; }
+    import yang-ext {prefix ext; revision-date "2013-07-09"; }
+
+    organization "Cisco Systems, Inc.";
+    contact "Robert Gallas";
+
+    description
+        "Base model for a topology where individual nodes can produce events.
+
+        Module implementing event source topology and encapped notification.
+
+        Copyright (c)2014 Cisco Systems, Inc. All rights reserved.
+
+        This program and the accompanying materials are made available
+        under the terms of the Eclipse Public License v1.0 which
+        accompanies this distribution, and is available at
+        http://www.eclipse.org/legal/epl-v10.html";
+
+    revision "2014-12-02" {
+        description "first revision";
+    }
+
+    // FIXME: expand this
+    typedef join-topic-status {
+        type enumeration {
+            enum up;
+            enum down;
+        }
+        description "Object status";
+    }
+
+    // FIXME: migrate to topology
+    typedef node-ref {
+        type leafref {
+            path "/inv:nodes/inv:node/inv:id";
+        }
+    }
+
+    grouping topology-event-source-type {
+        container topology-event-source {
+            presence "indicates an event source-aware topology";
+        }
+    }
+
+    rpc join-topic {
+        input {
+            leaf node {
+               ext:context-reference "inv:node-context";
+               type "instance-identifier";
+            }
+            leaf topic-id {
+                type aggr:topic-id;
+                description "in current implementation notification-pattern is defined by topic-id.
+                             By persisting topic definition we could omit notification-pattern";
+            }
+            leaf notification-pattern {
+                type aggr:notification-pattern;
+            }
+        }
+
+        output {
+            leaf status {
+                type join-topic-status;
+            }
+        }
+    }
+
+    augment "/nt:network-topology/nt:topology/nt:topology-types" {
+        uses topology-event-source-type;
+    }
+
+    augment "/nt:network-topology/nt:topology/nt:node" {
+        when "../../nt:topology-types/topology-event-source";
+        leaf event-source-node {
+            type node-ref;
+        }
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/pom.xml b/opendaylight/md-sal/messagebus-impl/pom.xml
new file mode 100644 (file)
index 0000000..8e088ba
--- /dev/null
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0"\r
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+    <modelVersion>4.0.0</modelVersion>\r
+\r
+    <parent>\r
+        <groupId>org.opendaylight.controller</groupId>\r
+        <artifactId>sal-parent</artifactId>\r
+        <version>1.2.0-SNAPSHOT</version>\r
+    </parent>\r
+\r
+    <artifactId>message-bus-impl</artifactId>\r
+    <name>${project.artifactId}</name>\r
+\r
+    <packaging>bundle</packaging>\r
+\r
+    <dependencies>\r
+        <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
+            <artifactId>sal-binding-api</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>sal-core-api</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>sal-common-util</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.yangtools</groupId>\r
+            <artifactId>yang-data-impl</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>config-api</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>message-bus-api</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>sal-binding-config</artifactId>\r
+        </dependency>\r
+    </dependencies>\r
+\r
+    <build>\r
+        <plugins>\r
+            <plugin>\r
+                <groupId>org.opendaylight.yangtools</groupId>\r
+                <artifactId>yang-maven-plugin</artifactId>\r
+                <executions>\r
+                    <execution>\r
+                        <goals>\r
+                            <goal>generate-sources</goal>\r
+                        </goals>\r
+                        <configuration>\r
+                            <codeGenerators>\r
+                                <generator>\r
+                                    <codeGeneratorClass>\r
+                                        org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl\r
+                                    </codeGeneratorClass>\r
+                                    <outputBaseDir>\r
+                                        ${project.build.directory}/generated-sources/sal\r
+                                    </outputBaseDir>\r
+                                </generator>\r
+                                <generator>\r
+                                    <codeGeneratorClass>\r
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator\r
+                                    </codeGeneratorClass>\r
+                                    <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>\r
+                                    <additionalConfiguration>\r
+                                        <namespaceToPackage1>\r
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang\r
+                                        </namespaceToPackage1>\r
+                                    </additionalConfiguration>\r
+                                </generator>\r
+                                <generator>\r
+                                    <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>\r
+                                    <outputBaseDir>target/site/models</outputBaseDir>\r
+                                </generator>\r
+                            </codeGenerators>\r
+                            <inspectDependencies>true</inspectDependencies>\r
+                        </configuration>\r
+                    </execution>\r
+                </executions>\r
+            </plugin>\r
+            <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
+                        <phase>generate-sources</phase>\r
+                        <goals>\r
+                            <goal>add-source</goal>\r
+                        </goals>\r
+                        <configuration>\r
+                            <sources>\r
+                                <source>${project.build.directory}/generated-sources/config</source>\r
+                            </sources>\r
+                        </configuration>\r
+                    </execution>\r
+                </executions>\r
+            </plugin>\r
+        </plugins>\r
+    </build>\r
+</project>\r
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/config/yang/messagebus/app/impl/MessageBusAppImplModule.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/config/yang/messagebus/app/impl/MessageBusAppImplModule.java
new file mode 100644 (file)
index 0000000..1c2b78a
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.messagebus.app.impl;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.mdsal.InitializationContext;
+import org.opendaylight.controller.mdsal.Providers;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class MessageBusAppImplModule extends org.opendaylight.controller.config.yang.messagebus.app.impl.AbstractMessageBusAppImplModule {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MessageBusAppImplModule.class);
+
+    private BundleContext bundleContext;
+
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public MessageBusAppImplModule( ModuleIdentifier identifier, DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public MessageBusAppImplModule( ModuleIdentifier identifier,
+                                    DependencyResolver dependencyResolver,
+                                    MessageBusAppImplModule oldModule,
+                                    java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation() {}
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        List<NamespaceToStream> namespaceMapping = getNamespaceToStream();
+        InitializationContext ic = new InitializationContext(namespaceMapping);
+
+        final Providers.BindingAware bap = new Providers.BindingAware(ic);
+        final Providers.BindingIndependent bip = new Providers.BindingIndependent(ic);
+
+        getBindingBrokerDependency().registerProvider(bap, getBundleContext());
+        getDomBrokerDependency().registerProvider(bip);
+
+        AutoCloseable closer = new AutoCloseable() {
+            @Override public void close()  {
+                closeProvider(bap);
+                closeProvider(bip);
+            }
+        };
+
+        return closer;
+    }
+
+    private void closeProvider(AutoCloseable closable) {
+        try {
+            closable.close();
+        } catch (Exception e) {
+            LOGGER.error("Exception while closing: {}\n Exception: {}", closable, e);
+        }
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/config/yang/messagebus/app/impl/MessageBusAppImplModuleFactory.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/config/yang/messagebus/app/impl/MessageBusAppImplModuleFactory.java
new file mode 100644 (file)
index 0000000..8bee2d1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: message-bus-app-impl yang module local name: messagebus-app-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Tue Feb 03 09:03:11 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.messagebus.app.impl;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+
+public class MessageBusAppImplModuleFactory extends org.opendaylight.controller.config.yang.messagebus.app.impl.AbstractMessageBusAppImplModuleFactory {
+    @Override
+    public Module createModule(String instanceName,
+                               DependencyResolver dependencyResolver,
+                               BundleContext bundleContext) {
+
+        MessageBusAppImplModule module =
+                (MessageBusAppImplModule) super.createModule(instanceName,
+                        dependencyResolver,
+                        bundleContext);
+
+        module.setBundleContext(bundleContext);
+
+        return module;
+    }
+
+    @Override
+    public Module createModule(String instanceName,
+                               DependencyResolver dependencyResolver,
+                               DynamicMBeanWithInstance old,
+                               BundleContext bundleContext)
+            throws Exception {
+
+        MessageBusAppImplModule module =
+                (MessageBusAppImplModule) super.createModule(instanceName,
+                        dependencyResolver,
+                        old,
+                        bundleContext);
+
+        module.setBundleContext(bundleContext);
+
+        return module;
+    }
+
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/DataStore.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/DataStore.java
new file mode 100644 (file)
index 0000000..a881fac
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.mdsal;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class DataStore {
+    private static final FutureCallback<Void> DEFAULT_CALLBACK =
+            new FutureCallback<Void>() {
+                public void onSuccess(Void result) {
+                    // TODO: Implement default behaviour
+                }
+
+                public void onFailure(Throwable t) {
+                    // TODO: Implement default behaviour
+                };
+            };
+
+    private final MdSAL mdSAL;
+
+    public DataStore(MdSAL mdSAL) {
+        this.mdSAL = mdSAL;
+    }
+
+    public ListenerRegistration<DataChangeListener> registerDataChangeListener(LogicalDatastoreType store,
+                                                                               InstanceIdentifier<?> path,
+                                                                               DataChangeListener listener,
+                                                                               AsyncDataBroker.DataChangeScope triggeringScope) {
+        return mdSAL.getDataBroker().registerDataChangeListener(store, path, listener, triggeringScope);
+    }
+
+    public <T extends DataObject> void asyncPUT(LogicalDatastoreType datastoreType,
+                                                InstanceIdentifier<T> path,
+                                                T data) {
+        asyncPUT(datastoreType, path, data, DEFAULT_CALLBACK);
+    }
+
+    public <T extends DataObject> void asyncPUT(LogicalDatastoreType datastoreType,
+                                                InstanceIdentifier<T> path,
+                                                T data,
+                                                FutureCallback<Void> callback) {
+        WriteTransaction tx = mdSAL.getDataBroker().newWriteOnlyTransaction();
+        tx.put(datastoreType, path, data, true);
+        execPut(tx, callback);
+    }
+
+    public <T extends DataObject> T read(LogicalDatastoreType datastoreType,
+                                         InstanceIdentifier<T> path) {
+
+        ReadOnlyTransaction tx = mdSAL.getDataBroker().newReadOnlyTransaction();
+        T result = null;
+
+        try {
+            result = tx.read(datastoreType, path).get().get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return result;
+    }
+
+    private static void execPut(WriteTransaction tx, FutureCallback<Void> callback) {
+        Futures.addCallback(tx.submit(), callback);
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/InitializationContext.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/InitializationContext.java
new file mode 100644 (file)
index 0000000..c73fb2a
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.mdsal;
+
+import org.opendaylight.controller.config.yang.messagebus.app.impl.NamespaceToStream;
+import org.opendaylight.controller.messagebus.app.impl.EventAggregator;
+import org.opendaylight.controller.messagebus.app.impl.EventSourceManager;
+import org.opendaylight.controller.messagebus.app.impl.EventSourceTopology;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class InitializationContext {
+    private static final Logger LOGGER = LoggerFactory.getLogger(InitializationContext.class);
+
+    private final MdSAL mdSal;
+    private final DataStore dataStore;
+    private final EventSourceTopology eventSourceTopology;
+    private final EventSourceManager eventSourceManager;
+    private final EventAggregator eventAggregator;
+
+    public InitializationContext(List<NamespaceToStream> namespaceMapping) {
+        this.mdSal = new MdSAL();
+        this.dataStore = new DataStore(mdSal);
+        this.eventSourceTopology = new EventSourceTopology(dataStore);
+        this.eventSourceManager = new EventSourceManager(dataStore, mdSal, eventSourceTopology, namespaceMapping);
+        this.eventAggregator = new EventAggregator(mdSal, eventSourceTopology);
+    }
+
+    public synchronized void set(BindingAwareBroker.ProviderContext session) {
+        mdSal.setBindingAwareContext(session);
+
+        if (mdSal.isReady()) {
+            initialize();
+        }
+    }
+
+    public synchronized void set(Broker.ProviderSession session) {
+        mdSal.setBindingIndependentContext(session);
+
+        if (mdSal.isReady()) {
+            initialize();
+        }
+    }
+
+    private void initialize() {
+        eventSourceTopology.mdsalReady();
+        eventSourceManager.mdsalReady();
+        eventAggregator.mdsalReady();
+
+        LOGGER.info("InitializationContext started.");
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/MdSAL.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/MdSAL.java
new file mode 100644 (file)
index 0000000..03b220a
--- /dev/null
@@ -0,0 +1,188 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.mdsal;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+import org.opendaylight.controller.sal.binding.api.mount.MountInstance;
+import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationService;
+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.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+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.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MdSAL {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MdSAL.class);
+
+    private BindingAwareBroker.ProviderContext bindingAwareContext;
+    private Broker.ProviderSession bindingIndependentContext;
+
+    // -----------------------------
+    // ----- FRAMEWORK METHODS -----
+    // -----------------------------
+    public void setBindingAwareContext(BindingAwareBroker.ProviderContext bindingAwareContext) {
+        this.bindingAwareContext = bindingAwareContext;
+    }
+
+    public void setBindingIndependentContext(Broker.ProviderSession bindingIndependentContext) {
+        this.bindingIndependentContext = bindingIndependentContext;
+    }
+
+    //TODO: We should hide brokers and expose functionalities instead
+    public DataBroker getDataBroker() {
+        return getBaSalService(DataBroker.class);
+    }
+
+    public synchronized boolean isReady() {
+        return (bindingAwareContext != null && bindingIndependentContext != null);
+    }
+
+    // -----------------------
+    // ----- API METHODS -----
+    // -----------------------
+    // TODO: Factor out API methods to interface
+    // method does not return registration object. Rather will hold references internally and manipulate using node id and API
+    public <T extends RpcService> void addRpcImplementation(Class<T> serviceInterface,
+                                                            T implementation)
+            throws IllegalStateException {
+        bindingAwareContext.addRpcImplementation(serviceInterface, implementation);
+    }
+
+    // method does not return registration object. Rather will hold references internally and manipulate using node id and API
+    public <T extends RpcService> void addRpcImplementation(Node node,
+                                                            Class<T> serviceInterface,
+                                                            T implementation)
+            throws IllegalStateException {
+        BindingAwareBroker.RoutedRpcRegistration<T> registration
+                = addRoutedRpcImplementation(serviceInterface, implementation);
+
+        NodeRef nodeRef = createNodeRef(node.getId());
+        registration.registerPath(NodeContext.class, nodeRef.getValue());
+    }
+
+    public ListenerRegistration<NotificationListener> addNotificationListener(String nodeId,
+                                                                              QName notification,
+                                                                              NotificationListener listener) {
+        YangInstanceIdentifier yii = inventoryNodeBIIdentifier(nodeId);
+
+        NotificationService notificationService =
+                getBiSalService(DOMMountPointService.class)
+                        .getMountPoint(yii)
+                        .get()
+                        .getService(NotificationPublishService.class)
+                        .get();
+
+        ListenerRegistration<NotificationListener> registration =
+                notificationService.addNotificationListener(notification, listener);
+
+        LOGGER.info("Notification listener registered for {}, at node {}", notification, nodeId);
+
+        return registration;
+    }
+
+    public ListenerRegistration<NotificationListener> addNotificationListener(QName notification,
+                                                                              NotificationListener listener) {
+        NotificationService notificationService =
+                getBiSalService(NotificationPublishService.class);
+
+        ListenerRegistration<NotificationListener> registration =
+                notificationService.addNotificationListener(notification, listener);
+
+        LOGGER.info("Notification listener registered for {}.", notification);
+
+        return registration;
+    }
+
+    public <T extends RpcService> T getRpcService(Class<T> serviceInterface) {
+        return bindingAwareContext.getRpcService(serviceInterface);
+    }
+
+    public <T extends RpcService> T getRpcService(String nodeId, Class<T> serviceInterface) {
+        MountProviderService mountProviderService = getBaSalService(MountProviderService.class);
+
+        InstanceIdentifier<Node> key = InstanceIdentifier.create(Nodes.class)
+                                                         .child(Node.class,
+                                                                 new NodeKey(new NodeId(nodeId)));
+
+        MountInstance mountPoint = mountProviderService.getMountPoint(key);
+        return mountPoint.getRpcService(serviceInterface);
+    }
+
+    public void publishNotification(CompositeNode notification) {
+        getBiSalService(NotificationPublishService.class).publish(notification);
+    }
+
+    public SchemaContext getSchemaContext(String nodeId) {
+        YangInstanceIdentifier yii = inventoryNodeBIIdentifier(nodeId);
+
+        SchemaContext schemaContext =
+                getBiSalService(DOMMountPointService.class)
+                        .getMountPoint(yii)
+                        .get().getSchemaContext();
+
+        return schemaContext;
+    }
+
+    // ---------------------------
+    // ----- UTILITY METHODS -----
+    // ---------------------------
+    private <T extends BindingAwareService> T getBaSalService(Class<T> service) {
+        return bindingAwareContext.getSALService(service);
+    }
+
+    private <T extends BrokerService> T getBiSalService(Class<T> service) {
+        return bindingIndependentContext.getService(service);
+    }
+
+    private static final String NODE_ID_NAME = "id";
+
+    public static YangInstanceIdentifier inventoryNodeBIIdentifier(String nodeId) {
+        return YangInstanceIdentifier.builder()
+                .node(Nodes.QNAME)
+                .nodeWithKey(Node.QNAME,
+                             QName.create(Node.QNAME.getNamespace(),
+                                          Node.QNAME.getRevision(),
+                                          NODE_ID_NAME),
+                             nodeId)
+                .build();
+    }
+
+    private <T extends RpcService> BindingAwareBroker.RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> serviceInterface,
+                                                                                                          T implementation)
+            throws IllegalStateException {
+        return bindingAwareContext.addRoutedRpcImplementation(serviceInterface, implementation);
+    }
+
+    public static NodeRef createNodeRef(NodeId nodeId) {
+        NodeKey nodeKey = new NodeKey(nodeId);
+        InstanceIdentifier<Node> path = InstanceIdentifier
+                .builder(Nodes.class)
+                .child(Node.class, nodeKey)
+                .build();
+        return new NodeRef(path);
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/Providers.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/mdsal/Providers.java
new file mode 100644 (file)
index 0000000..a28e588
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.mdsal;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.core.api.AbstractProvider;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Providers {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Providers.class);
+
+    public static class BindingAware implements BindingAwareProvider, AutoCloseable {
+        private final InitializationContext initializationContext;
+
+        public BindingAware(InitializationContext ic) {
+            this.initializationContext = ic;
+        }
+
+        @Override
+        public void onSessionInitiated(BindingAwareBroker.ProviderContext session) {
+            initializationContext.set(session);
+
+            LOGGER.info("BindingAwareBroker.ProviderContext initialized");
+        }
+
+        @Override
+        public void close() throws Exception {}
+    }
+
+    public static class BindingIndependent extends AbstractProvider implements AutoCloseable {
+        private final InitializationContext initializationContext;
+
+        public BindingIndependent(InitializationContext ic) {
+            this.initializationContext = ic;
+        }
+
+        @Override
+        public void onSessionInitiated(Broker.ProviderSession session) {
+            initializationContext.set(session);
+
+            LOGGER.info("Broker.ProviderSession initialized");
+        }
+
+        @Override
+        public void close() throws Exception {}
+    }
+
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventAggregator.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventAggregator.java
new file mode 100644 (file)
index 0000000..4b77bf2
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.messagebus.app.impl;
+
+import java.util.List;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.mdsal.MdSAL;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.CreateTopicInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.CreateTopicOutput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.CreateTopicOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.DestroyTopicInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.EventAggregatorService;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.NotificationPattern;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.Node1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// TODO: implement topic created notification
+public class EventAggregator implements EventAggregatorService {
+    private static final Logger LOGGER = LoggerFactory.getLogger(EventAggregator.class);
+
+    private final MdSAL mdSAL;
+    private final EventSourceTopology eventSourceTopology;
+
+    public EventAggregator(final MdSAL mdSAL, final EventSourceTopology eventSourceTopology) {
+        this.mdSAL = mdSAL;
+        this.eventSourceTopology = eventSourceTopology;
+    }
+
+    public void mdsalReady() {
+        mdSAL.addRpcImplementation(EventAggregatorService.class, this);
+    }
+
+    @Override
+    public Future<RpcResult<CreateTopicOutput>> createTopic(final CreateTopicInput input) {
+        LOGGER.info("Received Topic creation request: NotificationPattern -> {}, NodeIdPattern -> {}",
+                input.getNotificationPattern(),
+                input.getNodeIdPattern());
+
+        Topic topic = new Topic(new NotificationPattern(input.getNotificationPattern()), input.getNodeIdPattern().getValue(), mdSAL);
+
+        //# Make sure we capture all nodes from now on
+        eventSourceTopology.registerDataChangeListener(topic);
+
+        //# Notify existing nodes
+        //# Code reader note: Context of Node type is NetworkTopology
+        List<Node> nodes = eventSourceTopology.snapshot();
+        for (Node node : nodes) {
+            NodeId nodeIdToNotify = node.getAugmentation(Node1.class).getEventSourceNode();
+            topic.notifyNode(nodeIdToNotify);
+        }
+
+        CreateTopicOutput cto = new CreateTopicOutputBuilder()
+                .setTopicId(topic.getTopicId())
+                .build();
+
+        return Util.resultFor(cto);
+    }
+
+    @Override
+    public Future<RpcResult<Void>> destroyTopic(final DestroyTopicInput input) {
+        // 1. UNREGISTER DATA CHANGE LISTENER -> ?
+        // 2. CLOSE TOPIC
+        return null;
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventSourceManager.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventSourceManager.java
new file mode 100644 (file)
index 0000000..a84eddd
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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.messagebus.app.impl;
+
+import org.opendaylight.controller.config.yang.messagebus.app.impl.NamespaceToStream;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.mdsal.DataStore;
+import org.opendaylight.controller.mdsal.MdSAL;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.EventSourceService;
+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.netconf.node.inventory.rev140108.NetconfNode;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public final class EventSourceManager implements DataChangeListener {
+    private static final Logger LOGGER = LoggerFactory.getLogger(EventSourceManager.class);
+    private static final InstanceIdentifier<Node> INVENTORY_PATH = InstanceIdentifier.create(Nodes.class)
+                                                                                     .child(Node.class);
+    private final DataStore dataStore;
+    private final MdSAL mdSal;
+    private final EventSourceTopology eventSourceTopology;
+    private final Map<String, String> streamMap;
+
+    public EventSourceManager(DataStore dataStore,
+                              MdSAL mdSal,
+                              EventSourceTopology eventSourceTopology,
+                              List<NamespaceToStream> namespaceMapping) {
+        this.dataStore = dataStore;
+        this.mdSal = mdSal;
+        this.eventSourceTopology = eventSourceTopology;
+        this.streamMap = namespaceToStreamMapping(namespaceMapping);
+    }
+
+    private Map namespaceToStreamMapping(List<NamespaceToStream> namespaceMapping) {
+        Map<String, String> streamMap = new HashMap<>(namespaceMapping.size());
+
+        for (NamespaceToStream nToS  : namespaceMapping) {
+            streamMap.put(nToS.getUrnPrefix(), nToS.getStreamName());
+        }
+
+        return streamMap;
+    }
+
+    public void mdsalReady() {
+        dataStore.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                                             INVENTORY_PATH,
+                                             this,
+                                             DataBroker.DataChangeScope.SUBTREE);
+
+        LOGGER.info("EventSourceManager initialized.");
+    }
+
+    @Override
+    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event) {
+        //FIXME: Prevent creating new event source on subsequent changes in inventory, like disconnect.
+        LOGGER.debug("[DataChangeEvent<InstanceIdentifier<?>, DataObject>: {}]", event);
+
+        Node node = Util.getAffectedNode(event);
+        // we listen on node tree, therefore we should rather throw IllegalStateException when node is null
+        if ( node == null ) {
+            LOGGER.debug("OnDataChanged Event. Node is null.");
+            return;
+        }
+        if ( isNetconfNode(node) == false ) {
+            LOGGER.debug("OnDataChanged Event. Not a Netconf node.");
+            return;
+        }
+        if ( isEventSource(node) == false ) {
+            LOGGER.debug("OnDataChanged Event. Node an EventSource node.");
+            return;
+        }
+
+        NetconfEventSource netconfEventSource = new NetconfEventSource(mdSal,
+                                                                       node.getKey().getId().getValue(),
+                                                                       streamMap);
+        mdSal.addRpcImplementation(node, EventSourceService.class, netconfEventSource);
+
+        InstanceIdentifier<NetconfNode> nodeInstanceIdentifier =
+                InstanceIdentifier.create(Nodes.class)
+                        .child(Node.class, node.getKey())
+                        .augmentation(NetconfNode.class);
+
+        dataStore.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                nodeInstanceIdentifier,
+                netconfEventSource,
+                DataBroker.DataChangeScope.SUBTREE);
+
+        eventSourceTopology.insert(node);
+    }
+
+    private boolean isNetconfNode(Node node)  {
+        return node.getAugmentation(NetconfNode.class) != null ;
+    }
+
+    public boolean isEventSource(Node node) {
+        NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
+
+        return isEventSource(netconfNode);
+    }
+
+    private boolean isEventSource(NetconfNode node) {
+        for (String capability : node.getInitialCapability()) {
+            if(capability.startsWith("urn:ietf:params:xml:ns:netconf:notification")) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventSourceTopology.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/EventSourceTopology.java
new file mode 100644 (file)
index 0000000..c070097
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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.messagebus.app.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.mdsal.DataStore;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.Node1;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.Node1Builder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.TopologyTypes1;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.TopologyTypes1Builder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.topology.event.source.type.TopologyEventSource;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.topology.event.source.type.TopologyEventSourceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class EventSourceTopology {
+    private static final Logger LOGGER = LoggerFactory.getLogger(EventSourceTopology.class);
+
+    private static final String topologyId = "EVENT-SOURCE-TOPOLOGY" ;
+    private static final TopologyKey topologyKey = new TopologyKey(new TopologyId(topologyId));
+    private static final LogicalDatastoreType datastoreType = LogicalDatastoreType.OPERATIONAL;
+
+    private static final InstanceIdentifier<Topology> topologyInstanceIdentifier =
+            InstanceIdentifier.create(NetworkTopology.class)
+                    .child(Topology.class, topologyKey);
+
+    private static final InstanceIdentifier<TopologyTypes1> topologyTypeInstanceIdentifier =
+            topologyInstanceIdentifier
+                    .child(TopologyTypes.class)
+                    .augmentation(TopologyTypes1.class);
+
+    private static final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
+                                            .network.topology.rev131021.network.topology.topology.Node> eventSourceTopologyPath =
+            InstanceIdentifier.create(NetworkTopology.class)
+                    .child(Topology.class)
+                    .child(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
+                            .network.topology.rev131021.network.topology.topology.Node.class);
+
+    private final Map<DataChangeListener, ListenerRegistration<DataChangeListener>> registrations =
+            new ConcurrentHashMap<>();
+
+    private final DataStore dataStore;
+
+    public EventSourceTopology(DataStore dataStore) {
+        this.dataStore = dataStore;
+    }
+
+    public void mdsalReady() {
+        TopologyEventSource topologySource = new TopologyEventSourceBuilder().build();
+        TopologyTypes1 topologyTypeAugment = new TopologyTypes1Builder().setTopologyEventSource(topologySource).build();
+
+        dataStore.asyncPUT(datastoreType, topologyTypeInstanceIdentifier, topologyTypeAugment);
+    }
+
+    public void insert(Node node) {
+        String nodeId = node.getKey().getId().getValue();
+        NodeKey nodeKey = new NodeKey(new NodeId(nodeId));
+        InstanceIdentifier<Node1> topologyNodeAugment
+                = topologyInstanceIdentifier
+                .child(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
+                        .network.topology.rev131021.network.topology.topology.Node.class, nodeKey)
+                .augmentation(Node1.class);
+
+        Node1 nodeAgument = new Node1Builder().setEventSourceNode(node.getId()).build();
+        dataStore.asyncPUT(datastoreType, topologyNodeAugment, nodeAgument);
+    }
+
+    // TODO: Should we expose this functioanlity over RPC?
+    public List<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
+                .network.topology.rev131021.network.topology.topology.Node> snapshot() {
+        Topology topology = dataStore.read(datastoreType, topologyInstanceIdentifier);
+        return topology.getNode();
+    }
+
+    public void registerDataChangeListener(DataChangeListener listener) {
+        ListenerRegistration<DataChangeListener> listenerRegistration = dataStore.registerDataChangeListener(datastoreType,
+                eventSourceTopologyPath,
+                listener,
+                DataBroker.DataChangeScope.SUBTREE);
+
+        registrations.put(listener, listenerRegistration);
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/NetconfEventSource.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/NetconfEventSource.java
new file mode 100644 (file)
index 0000000..9c0697f
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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.messagebus.app.impl;
+
+import com.google.common.base.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+import java.util.regex.Pattern;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.mdsal.MdSAL;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.NotificationPattern;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.TopicNotification;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.EventSourceService;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.JoinTopicInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.JoinTopicOutput;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.inventory.rev140108.NetconfNode;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfEventSource implements EventSourceService, NotificationListener, DataChangeListener {
+    private static final Logger LOGGER = LoggerFactory.getLogger(NetconfEventSource.class);
+
+    private final MdSAL mdSal;
+    private final String nodeId;
+
+    private final List<String> activeStreams = new ArrayList<>();
+
+    private final Map<String, String> urnPrefixToStreamMap;
+
+    public NetconfEventSource(final MdSAL mdSal, final String nodeId, final Map<String, String> streamMap) {
+        Preconditions.checkNotNull(mdSal);
+        Preconditions.checkNotNull(nodeId);
+
+        this.mdSal = mdSal;
+        this.nodeId = nodeId;
+        this.urnPrefixToStreamMap = streamMap;
+
+        LOGGER.info("NetconfEventSource [{}] created.", nodeId);
+    }
+
+    @Override
+    public Future<RpcResult<JoinTopicOutput>> joinTopic(final JoinTopicInput input) {
+        final NotificationPattern notificationPattern = input.getNotificationPattern();
+
+        // FIXME: default language should already be regex
+        final String regex = Util.wildcardToRegex(notificationPattern.getValue());
+
+        final Pattern pattern = Pattern.compile(regex);
+        List<QName> matchingNotifications = Util.expandQname(availableNotifications(), pattern);
+        registerNotificationListener(matchingNotifications);
+        return null;
+    }
+
+    private List<QName> availableNotifications() {
+        // FIXME: use SchemaContextListener to get changes asynchronously
+        Set<NotificationDefinition> availableNotifications = mdSal.getSchemaContext(nodeId).getNotifications();
+        List<QName> qNs = new ArrayList<>(availableNotifications.size());
+        for (NotificationDefinition nd : availableNotifications) {
+            qNs.add(nd.getQName());
+        }
+
+        return qNs;
+    }
+
+    private void registerNotificationListener(final List<QName> notificationsToSubscribe) {
+        for (QName qName : notificationsToSubscribe) {
+            startSubscription(qName);
+            // FIXME: do not lose this registration
+            final ListenerRegistration<NotificationListener> reg = mdSal.addNotificationListener(nodeId, qName, this);
+        }
+    }
+
+    private synchronized void startSubscription(final QName qName) {
+        String streamName = resolveStream(qName);
+
+        if (streamIsActive(streamName) == false) {
+            LOGGER.info("Stream {} is not active on node {}. Will subscribe.", streamName, nodeId);
+            startSubscription(streamName);
+        }
+    }
+
+    private synchronized void resubscribeToActiveStreams() {
+        for (String streamName : activeStreams) {
+            startSubscription(streamName);
+        }
+    }
+
+    private synchronized void startSubscription(final String streamName) {
+        CreateSubscriptionInput subscriptionInput = getSubscriptionInput(streamName);
+        mdSal.getRpcService(nodeId, NotificationsService.class).createSubscription(subscriptionInput);
+        activeStreams.add(streamName);
+    }
+
+    private static CreateSubscriptionInput getSubscriptionInput(final String streamName) {
+        CreateSubscriptionInputBuilder csib = new CreateSubscriptionInputBuilder();
+        csib.setStream(new StreamNameType(streamName));
+        return csib.build();
+    }
+
+    private String resolveStream(final QName qName) {
+        String streamName = null;
+
+        for (Map.Entry<String, String> entry : urnPrefixToStreamMap.entrySet()) {
+            String nameSpace = qName.getNamespace().toString();
+            String urnPrefix = entry.getKey();
+            if( nameSpace.startsWith(urnPrefix) ) {
+                streamName = entry.getValue();
+                break;
+            }
+        }
+
+        return streamName;
+    }
+
+    private boolean streamIsActive(final String streamName) {
+        return activeStreams.contains(streamName);
+    }
+
+    // PASS
+    @Override public Set<QName> getSupportedNotifications() {
+        return null;
+    }
+
+    @Override
+    public void onNotification(final CompositeNode notification) {
+        LOGGER.info("NetconfEventSource {} received notification {}. Will publish to MD-SAL.", nodeId, notification);
+        ImmutableCompositeNode payload = ImmutableCompositeNode.builder()
+                .setQName(QName.create(TopicNotification.QNAME, "payload"))
+                .add(notification).toInstance();
+        ImmutableCompositeNode icn = ImmutableCompositeNode.builder()
+                .setQName(TopicNotification.QNAME)
+                .add(payload)
+                .addLeaf("event-source", nodeId)
+                .toInstance();
+
+        mdSal.publishNotification(icn);
+    }
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        boolean wasConnected = false;
+        boolean nowConnected = false;
+
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> changeEntry : change.getOriginalData().entrySet()) {
+            if ( isNetconfNode(changeEntry) ) {
+                NetconfNode nn = (NetconfNode)changeEntry.getValue();
+                wasConnected = nn.isConnected();
+            }
+        }
+
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> changeEntry : change.getUpdatedData().entrySet()) {
+            if ( isNetconfNode(changeEntry) ) {
+                NetconfNode nn = (NetconfNode)changeEntry.getValue();
+                nowConnected = nn.isConnected();
+            }
+        }
+
+        if (wasConnected == false && nowConnected == true) {
+            resubscribeToActiveStreams();
+        }
+    }
+
+    private static boolean isNetconfNode(final Map.Entry<InstanceIdentifier<?>, DataObject> changeEntry )  {
+        return NetconfNode.class.equals(changeEntry.getKey().getTargetType());
+    }
+
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/Topic.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/Topic.java
new file mode 100644 (file)
index 0000000..aebde0c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.messagebus.app.impl;
+
+import com.google.common.base.Preconditions;
+import java.util.regex.Pattern;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.mdsal.MdSAL;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.NotificationPattern;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.TopicId;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.EventSourceService;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.JoinTopicInput;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventsource.rev141202.JoinTopicInputBuilder;
+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.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.LoggerFactory;
+
+public class Topic implements DataChangeListener {
+    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(Topic.class);
+    private final NotificationPattern notificationPattern;
+    private final Pattern nodeIdPattern;
+    private final TopicId topicId;
+    private final MdSAL mdSal;
+
+    public Topic(final NotificationPattern notificationPattern, final String nodeIdPattern, final MdSAL mdSal) {
+        this.notificationPattern = Preconditions.checkNotNull(notificationPattern);
+
+        // FIXME: regex should be the language of nodeIdPattern
+        final String regex = Util.wildcardToRegex(nodeIdPattern);
+        this.nodeIdPattern = Pattern.compile(regex);
+        this.mdSal = Preconditions.checkNotNull(mdSal);
+
+        // FIXME: We need to perform some salting in order to make
+        //        the topic IDs less predictable.
+        this.topicId = new TopicId(Util.md5String(notificationPattern + nodeIdPattern));
+    }
+
+    public TopicId getTopicId() {
+        return topicId;
+    }
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event) {
+        // TODO: affected must return topologyNode !!!
+        final Node node = Util.getAffectedNode(event);
+        if (nodeIdPattern.matcher(node.getId().getValue()).matches()) {
+            notifyNode(node.getId());
+        } else {
+            LOG.debug("Skipping node {}", node.getId());
+        }
+    }
+
+    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.");
+        }
+
+        ess.joinTopic(jti);
+    }
+
+    private JoinTopicInput getJoinTopicInputArgument(final NodeId nodeId) {
+        NodeRef nodeRef = MdSAL.createNodeRef(nodeId);
+        JoinTopicInput jti =
+                new JoinTopicInputBuilder()
+                        .setNode(nodeRef.getValue())
+                        .setTopicId(topicId)
+                        .setNotificationPattern(notificationPattern)
+                        .build();
+        return jti;
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/Util.java b/opendaylight/md-sal/messagebus-impl/src/main/java/org/opendaylight/controller/messagebus/app/impl/Util.java
new file mode 100644 (file)
index 0000000..9927d85
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.messagebus.app.impl;
+
+import com.google.common.util.concurrent.Futures;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.regex.Pattern;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public final class Util {
+    private static final MessageDigest messageDigestTemplate = getDigestInstance();
+
+    private static MessageDigest getDigestInstance() {
+        try {
+            return MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("Unable to get MD5 instance");
+        }
+    }
+
+    public static String md5String(final String inputString) {
+
+        try {
+            MessageDigest md = (MessageDigest)messageDigestTemplate.clone();
+            md.update(inputString.getBytes("UTF-8"), 0, inputString.length());
+            return new BigInteger(1, md.digest()).toString(16);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to get MD5 instance");
+        }
+    }
+
+    public static <T> Future<RpcResult<T>> resultFor(final T output) {
+        RpcResult<T> result = Rpcs.getRpcResult(true, output, Collections.<RpcError>emptyList());
+        return Futures.immediateFuture(result);
+    }
+
+    /**
+     * Extracts affected node from data change event.
+     * @param event
+     * @return
+     */
+    public static Node getAffectedNode(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> event) {
+        // TODO: expect listener method to be called even when change impact node
+        // TODO: test with change.getCreatedData()
+        for (Map.Entry<InstanceIdentifier<?>, DataObject> changeEntry : event.getUpdatedData().entrySet()) {
+            if (isNode(changeEntry)) {
+                return (Node) changeEntry.getValue();
+            }
+        }
+
+        return null;
+    }
+
+    private static boolean isNode(final Map.Entry<InstanceIdentifier<?>, DataObject> changeEntry )  {
+        return Node.class.equals(changeEntry.getKey().getTargetType());
+    }
+
+    /**
+     * Method filters qnames based on wildcard strings
+     *
+     * @param availableQnames
+     * @param patterh matching pattern
+     * @return list of filtered qnames
+     */
+    public static List<QName> expandQname(final List<QName> availableQnames, final Pattern pattern) {
+        List<QName> matchingQnames = new ArrayList<>();
+
+        for (QName qname : availableQnames) {
+            String namespace = qname.getNamespace().toString();
+            if (pattern.matcher(namespace).matches()) {
+                matchingQnames.add(qname);
+            }
+        }
+
+        return matchingQnames;
+    }
+
+    /**
+     * CREDIT to http://www.rgagnon.com/javadetails/java-0515.html
+     * @param wildcard
+     * @return
+     */
+    static String wildcardToRegex(final String wildcard){
+        StringBuffer s = new StringBuffer(wildcard.length());
+        s.append('^');
+        for (char c : wildcard.toCharArray()) {
+            switch(c) {
+                case '*':
+                    s.append(".*");
+                    break;
+                case '?':
+                    s.append('.');
+                    break;
+                // escape special regexp-characters
+                case '(':
+                case ')':
+                case '[':
+                case ']':
+                case '$':
+                case '^':
+                case '.':
+                case '{':
+                case '}':
+                case '|':
+                case '\\':
+                    s.append("\\");
+                    s.append(c);
+                    break;
+                default:
+                    s.append(c);
+                    break;
+            }
+        }
+        s.append('$');
+        return s.toString();
+    }
+}
diff --git a/opendaylight/md-sal/messagebus-impl/src/main/yang/messagebus-app-impl.yang b/opendaylight/md-sal/messagebus-impl/src/main/yang/messagebus-app-impl.yang
new file mode 100644 (file)
index 0000000..bed6b10
--- /dev/null
@@ -0,0 +1,64 @@
+module messagebus-app-impl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:messagebus:app:impl";
+    prefix "binding-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding {prefix sal;}
+    import opendaylight-md-sal-dom {prefix dom;}
+
+
+    description
+        "Service definition for Message Bus application implementation.";
+    revision "2015-02-03" {
+        description "Second revision. Message Bus opensourcing";
+    }
+
+    identity messagebus-app-impl {
+        base config:module-type;
+        config:java-name-prefix MessageBusAppImpl;
+    }
+    
+    augment "/config:modules/config:module/config:configuration" {
+        case messagebus-app-impl {
+            when "/config:modules/config:module/config:type = 'messagebus-app-impl'";
+            
+            container binding-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity sal:binding-broker-osgi-registry;
+                    }
+                }
+            }
+
+            container dom-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity dom:dom-broker-osgi-registry;
+                    }
+                }
+            }
+
+            list namespace-to-stream {
+                key urn-prefix;
+
+                leaf urn-prefix {
+                    type string;
+                }
+
+                leaf stream-name {
+                    type string;
+                }
+            }
+        }
+    }
+    
+    augment "/config:modules/config:module/config:state" {
+        case messagebus-app-impl {
+            when "/config:modules/config:module/config:type = 'messagebus-app-impl'";
+        }
+    }
+}
\ No newline at end of file
index 1743b62180a8519afcaddaf892c499a11ad9778e..bdeb8a65a8c2aeac617d34286bae46404767df35 100644 (file)
 
     <!-- Clustering -->
     <module>sal-remoterpc-connector</module>
+
+    <!-- Message Bus -->
+    <module>messagebus-api</module>
+    <module>messagebus-impl</module>
   </modules>
 
   <build>
index d1c3fefee8309208a6df6fe9b539a10ee000ddef..e2aa16918e8ed0354f8543f8edd74b89474e4072 100644 (file)
@@ -41,7 +41,7 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
     }
 
     protected int adjustedIndex(long logEntryIndex) {
-        if(snapshotIndex < 0){
+        if (snapshotIndex < 0) {
             return (int) logEntryIndex;
         }
         return (int) (logEntryIndex - (snapshotIndex + 1));
@@ -134,6 +134,11 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
        return journal.size();
     }
 
+    @Override
+    public int dataSize() {
+        return dataSize;
+    }
+
     @Override
     public boolean isPresent(long logEntryIndex) {
         if (logEntryIndex > lastIndex()) {
@@ -200,6 +205,11 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
         previousSnapshotIndex = -1;
         previousSnapshotTerm = -1;
         dataSize = 0;
+        // need to recalc the datasize based on the entries left after precommit.
+        for(ReplicatedLogEntry logEntry : journal) {
+            dataSize += logEntry.size();
+        }
+
     }
 
     @Override
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 1f446c72f1ee9eccef904866236c1ec5ea235fb9..3ec8cc5c5817d92825ba882101d21c5b437863cd 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;
@@ -31,16 +32,13 @@ import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply;
 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.AbstractRaftActorBehavior;
 import org.opendaylight.controller.cluster.raft.behaviors.Follower;
 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
-import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
-import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -85,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());
 
     /**
@@ -281,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(),
@@ -358,13 +365,6 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
             handleCaptureSnapshotReply(((CaptureSnapshotReply) message).getSnapshot());
 
         } else {
-            if (!(message instanceof AppendEntriesMessages.AppendEntries)
-                && !(message instanceof AppendEntriesReply) && !(message instanceof SendHeartBeat)) {
-                if(LOG.isDebugEnabled()) {
-                    LOG.debug("{}: onReceiveCommand: message: {}", persistenceId(), message.getClass());
-                }
-            }
-
             RaftActorBehavior oldBehavior = currentBehavior;
             currentBehavior = currentBehavior.handleMessage(getSender(), message);
 
@@ -573,7 +573,7 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
     /**
      * This method is called during recovery to reconstruct the state of the actor.
      *
-     * @param snapshot A snapshot of the state of the actor
+     * @param snapshotBytes A snapshot of the state of the actor
      */
     protected abstract void applyRecoverySnapshot(byte[] snapshotBytes);
 
@@ -668,12 +668,21 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
 
         LOG.info("{}: Persisting of snapshot done:{}", persistenceId(), sn.getLogMessage());
 
-        //be greedy and remove entries from in-mem journal which are in the snapshot
-        // and update snapshotIndex and snapshotTerm without waiting for the success,
+        long dataThreshold = Runtime.getRuntime().totalMemory() *
+                getRaftActorContext().getConfigParams().getSnapshotDataThresholdPercentage() / 100;
+        if (context.getReplicatedLog().dataSize() > dataThreshold) {
+            // if memory is less, clear the log based on lastApplied.
+            // this could/should only happen if one of the followers is down
+            // as normally we keep removing from the log when its replicated to all.
+            context.getReplicatedLog().snapshotPreCommit(captureSnapshot.getLastAppliedIndex(),
+                    captureSnapshot.getLastAppliedTerm());
 
-        context.getReplicatedLog().snapshotPreCommit(
-            captureSnapshot.getLastAppliedIndex(),
-            captureSnapshot.getLastAppliedTerm());
+        } else {
+            // clear the log based on replicatedToAllIndex
+            context.getReplicatedLog().snapshotPreCommit(captureSnapshot.getReplicatedToAllIndex(),
+                    captureSnapshot.getReplicatedToAllTerm());
+        }
+        getCurrentBehavior().setReplicatedToAllIndex(captureSnapshot.getReplicatedToAllIndex());
 
         LOG.info("{}: Removed in-memory snapshotted entries, adjusted snaphsotIndex:{} " +
             "and term:{}", persistenceId(), captureSnapshot.getLastAppliedIndex(),
@@ -717,13 +726,14 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
             // FIXME: Maybe this should be done after the command is saved
             journal.subList(adjustedIndex , journal.size()).clear();
 
-            persistence().persist(new DeleteEntries(adjustedIndex), new Procedure<DeleteEntries>(){
+            persistence().persist(new DeleteEntries(adjustedIndex), new Procedure<DeleteEntries>() {
 
-                @Override public void apply(DeleteEntries param)
-                    throws Exception {
+                @Override
+                public void apply(DeleteEntries param)
+                        throws Exception {
                     //FIXME : Doing nothing for now
                     dataSize = 0;
-                    for(ReplicatedLogEntry entry : journal){
+                    for (ReplicatedLogEntry entry : journal) {
                         dataSize += entry.size();
                     }
                 }
@@ -735,11 +745,6 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
             appendAndPersist(replicatedLogEntry, null);
         }
 
-        @Override
-        public int dataSize() {
-            return dataSize;
-        }
-
         public void appendAndPersist(
             final ReplicatedLogEntry replicatedLogEntry,
             final Procedure<ReplicatedLogEntry> callback)  {
@@ -766,7 +771,7 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
                         long dataSizeForCheck = dataSize;
 
                         dataSizeSinceLastSnapshot += logEntrySize;
-                        long journalSize = lastIndex()+1;
+                        long journalSize = lastIndex() + 1;
 
                         if(!hasFollowers()) {
                             // When we do not have followers we do not maintain an in-memory log
@@ -793,7 +798,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;
 
@@ -817,12 +824,15 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor {
                             }
 
                             // send a CaptureSnapshot to self to make the expensive operation async.
-                            getSelf().tell(new CaptureSnapshot(
-                                lastIndex(), lastTerm(), lastAppliedIndex, lastAppliedTerm),
+                            long replicatedToAllIndex = getCurrentBehavior().getReplicatedToAllIndex();
+                            ReplicatedLogEntry replicatedToAllEntry = context.getReplicatedLog().get(replicatedToAllIndex);
+                            getSelf().tell(new CaptureSnapshot(lastIndex(), lastTerm(), lastAppliedIndex, lastAppliedTerm,
+                                (replicatedToAllEntry != null ? replicatedToAllEntry.getIndex() : -1),
+                                (replicatedToAllEntry != null ? replicatedToAllEntry.getTerm() : -1)),
                                 null);
                             context.setSnapshotCaptureInitiated(true);
                         }
-                        if(callback != null){
+                        if (callback != null){
                             callback.apply(replicatedLogEntry);
                         }
                     }
index 80b7ad90d05dbb1e9fe45ec57a65a44dedfe4463..82d0839bee772bd8efba88a8d1392ab1d336ff1c 100644 (file)
@@ -145,14 +145,14 @@ public interface ReplicatedLog {
      * sets snapshot term
      * @param snapshotTerm
      */
-    public void setSnapshotTerm(long snapshotTerm);
+    void setSnapshotTerm(long snapshotTerm);
 
     /**
      * Clears the journal entries with startIndex(inclusive) and endIndex (exclusive)
      * @param startIndex
      * @param endIndex
      */
-    public void clear(int startIndex, int endIndex);
+    void clear(int startIndex, int endIndex);
 
     /**
      * Handles all the bookkeeping in order to perform a rollback in the
@@ -160,20 +160,21 @@ public interface ReplicatedLog {
      * @param snapshotCapturedIndex
      * @param snapshotCapturedTerm
      */
-    public void snapshotPreCommit(long snapshotCapturedIndex, long snapshotCapturedTerm);
+    void snapshotPreCommit(long snapshotCapturedIndex, long snapshotCapturedTerm);
 
     /**
      * Sets the Replicated log to state after snapshot success.
      */
-    public void snapshotCommit();
+    void snapshotCommit();
 
     /**
      * Restores the replicated log to a state in the event of a save snapshot failure
      */
-    public void snapshotRollback();
+    void snapshotRollback();
 
     /**
      * Size of the data in the log (in bytes)
      */
-    public int dataSize();
+    int dataSize();
+
 }
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 d4dd3350f30b120bf965c885e3319152db9a2c38..a96b1e435cf88df201be0c344908143b29166334 100644 (file)
@@ -14,19 +14,23 @@ public class CaptureSnapshot {
     private long lastIndex;
     private long lastTerm;
     private boolean installSnapshotInitiated;
+    private long replicatedToAllIndex;
+    private long replicatedToAllTerm;
 
     public CaptureSnapshot(long lastIndex, long lastTerm,
-        long lastAppliedIndex, long lastAppliedTerm) {
-        this(lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm, false);
+        long lastAppliedIndex, long lastAppliedTerm, long replicatedToAllIndex, long replicatedToAllTerm) {
+        this(lastIndex, lastTerm, lastAppliedIndex, lastAppliedTerm, replicatedToAllIndex , replicatedToAllTerm, false);
     }
 
     public CaptureSnapshot(long lastIndex, long lastTerm,long lastAppliedIndex,
-        long lastAppliedTerm, boolean installSnapshotInitiated) {
+        long lastAppliedTerm, long replicatedToAllIndex, long replicatedToAllTerm, boolean installSnapshotInitiated) {
         this.lastIndex = lastIndex;
         this.lastTerm = lastTerm;
         this.lastAppliedIndex = lastAppliedIndex;
         this.lastAppliedTerm = lastAppliedTerm;
         this.installSnapshotInitiated = installSnapshotInitiated;
+        this.replicatedToAllIndex = replicatedToAllIndex;
+        this.replicatedToAllTerm = replicatedToAllTerm;
     }
 
     public long getLastAppliedIndex() {
@@ -48,4 +52,12 @@ public class CaptureSnapshot {
     public boolean isInstallSnapshotInitiated() {
         return installSnapshotInitiated;
     }
+
+    public long getReplicatedToAllIndex() {
+        return replicatedToAllIndex;
+    }
+
+    public long getReplicatedToAllTerm() {
+        return replicatedToAllTerm;
+    }
 }
index 9b6c08857a50d50e81065c52c39c6c5469687ad9..1552096ef15aed6bf8f941a1c24474c9ca8cbe44 100644 (file)
@@ -34,7 +34,6 @@ 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.CaptureSnapshot;
-import org.opendaylight.controller.cluster.raft.base.messages.InitiateInstallSnapshot;
 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;
@@ -92,10 +91,8 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
 
     private Optional<ByteString> snapshot;
 
-    private long replicatedToAllIndex = -1;
-
     public AbstractLeader(RaftActorContext context) {
-        super(context);
+        super(context, RaftState.Leader);
 
         final Builder<String, FollowerLogInformation> ftlBuilder = ImmutableMap.builder();
         for (String followerId : context.getPeerAddresses().keySet()) {
@@ -110,7 +107,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
 
         leaderId = context.getId();
 
-        LOG.debug("{}: Election: Leader has following peers: {}", context.getId(), getFollowerIds());
+        LOG.debug("{}: Election: Leader has following peers: {}", logName(), getFollowerIds());
 
         minReplicationCount = getMajorityVoteCount(getFollowerIds().size());
 
@@ -128,7 +125,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
         // Upon election: send initial empty AppendEntries RPCs
         // (heartbeat) to each server; repeat during idle periods to
         // prevent election timeouts (§5.2)
-        sendAppendEntries(0);
+        sendAppendEntries(0, false);
     }
 
     /**
@@ -140,10 +137,6 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
         return followerToLog.keySet();
     }
 
-    private Optional<ByteString> getSnapshot() {
-        return snapshot;
-    }
-
     @VisibleForTesting
     void setSnapshot(Optional<ByteString> snapshot) {
         this.snapshot = snapshot;
@@ -153,9 +146,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
     protected RaftActorBehavior handleAppendEntries(ActorRef sender,
         AppendEntries appendEntries) {
 
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: handleAppendEntries: {}", context.getId(), appendEntries);
-        }
+        LOG.debug("{}: handleAppendEntries: {}", logName(), appendEntries);
 
         return this;
     }
@@ -164,10 +155,10 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
     protected RaftActorBehavior handleAppendEntriesReply(ActorRef sender,
         AppendEntriesReply appendEntriesReply) {
 
-        if(! appendEntriesReply.isSuccess()) {
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: handleAppendEntriesReply: {}", context.getId(), appendEntriesReply);
-            }
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("{}: handleAppendEntriesReply: {}", logName(), appendEntriesReply);
+        } else if(LOG.isDebugEnabled() && !appendEntriesReply.isSuccess()) {
+            LOG.debug("{}: handleAppendEntriesReply: {}", logName(), appendEntriesReply);
         }
 
         // Update the FollowerLogInformation
@@ -176,10 +167,18 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             followerToLog.get(followerId);
 
         if(followerLogInformation == null){
-            LOG.error("{}: handleAppendEntriesReply - unknown follower {}", context.getId(), followerId);
+            LOG.error("{}: handleAppendEntriesReply - unknown follower {}", logName(), followerId);
             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()) {
@@ -224,6 +223,9 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
 
         // Apply the change to the state machine
         if (context.getCommitIndex() > context.getLastApplied()) {
+            LOG.debug("{}: handleAppendEntriesReply: applying to log - commitIndex: {}, lastAppliedIndex: {}",
+                    logName(), context.getCommitIndex(), context.getLastApplied());
+
             applyLogToStateMachine(context.getCommitIndex());
         }
 
@@ -232,20 +234,21 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
         }
 
         //Send the next log entry immediately, if possible, no need to wait for heartbeat to trigger that event
-        sendUpdatesToFollower(followerId, followerLogInformation, false);
+        sendUpdatesToFollower(followerId, followerLogInformation, false, false);
         return this;
     }
 
     private void purgeInMemoryLog() {
-        //find the lowest index across followers which has been replicated to all. -1 if there are no followers.
+        //find the lowest index across followers which has been replicated to all.
+        // lastApplied if there are no followers, so that we keep clearing the log for single-node
         // we would delete the in-mem log from that index on, in-order to minimize mem usage
         // we would also share this info thru AE with the followers so that they can delete their log entries as well.
-        long minReplicatedToAllIndex = followerToLog.isEmpty() ? -1 : Long.MAX_VALUE;
+        long minReplicatedToAllIndex = followerToLog.isEmpty() ? context.getLastApplied() : Long.MAX_VALUE;
         for (FollowerLogInformation info : followerToLog.values()) {
             minReplicatedToAllIndex = Math.min(minReplicatedToAllIndex, info.getMatchIndex());
         }
 
-        replicatedToAllIndex = fakeSnapshot(minReplicatedToAllIndex, replicatedToAllIndex);
+        super.performSnapshotWithoutCapture(minReplicatedToAllIndex);
     }
 
     @Override
@@ -278,10 +281,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
         return this;
     }
 
-    @Override
-    public RaftState state() {
-        return RaftState.Leader;
-    }
+    protected void beforeSendHeartbeat(){}
 
     @Override
     public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
@@ -295,8 +295,8 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             // set currentTerm = T, convert to follower (§5.1)
             // This applies to all RPC messages and responses
             if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()) {
-                LOG.debug("{}: Term {} in \"{}\" message is greater than leader's term {}", context.getId(),
-                        rpc.getTerm(), rpc, context.getTermInformation().getCurrentTerm());
+                LOG.debug("{}: Term {} in \"{}\" message is greater than leader's term {} - switching to Follower",
+                        logName(), rpc.getTerm(), rpc, context.getTermInformation().getCurrentTerm());
 
                 context.getTermInformation().updateAndPersist(rpc.getTerm(), null);
 
@@ -306,12 +306,10 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
 
         try {
             if (message instanceof SendHeartBeat) {
+                beforeSendHeartbeat();
                 sendHeartBeat();
                 return this;
 
-            } else if(message instanceof InitiateInstallSnapshot) {
-                installSnapshotIfNeeded();
-
             } else if(message instanceof SendInstallSnapshot) {
                 // received from RaftActor
                 setSnapshot(Optional.of(((SendInstallSnapshot) message).getSnapshot()));
@@ -332,12 +330,14 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
     }
 
     private void handleInstallSnapshotReply(InstallSnapshotReply reply) {
+        LOG.debug("{}: handleInstallSnapshotReply: {}", logName(), reply);
+
         String followerId = reply.getFollowerId();
         FollowerToSnapshot followerToSnapshot = mapFollowerToSnapshot.get(followerId);
 
         if (followerToSnapshot == null) {
             LOG.error("{}: FollowerId {} in InstallSnapshotReply not known to Leader",
-                    context.getId(), followerId);
+                    logName(), followerId);
             return;
         }
 
@@ -351,8 +351,8 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
                     //this was the last chunk reply
                     if(LOG.isDebugEnabled()) {
                         LOG.debug("{}: InstallSnapshotReply received, " +
-                                "last chunk received, Chunk:{}. Follower:{} Setting nextIndex:{}",
-                                context.getId(), reply.getChunkIndex(), followerId,
+                                "last chunk received, Chunk: {}. Follower: {} Setting nextIndex: {}",
+                                logName(), reply.getChunkIndex(), followerId,
                             context.getReplicatedLog().getSnapshotIndex() + 1
                         );
                     }
@@ -363,10 +363,9 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
                         context.getReplicatedLog().getSnapshotIndex() + 1);
                     mapFollowerToSnapshot.remove(followerId);
 
-                    if(LOG.isDebugEnabled()) {
-                        LOG.debug("{}: followerToLog.get(followerId).getNextIndex()=" +
-                                context.getId(), followerToLog.get(followerId).getNextIndex());
-                    }
+                    LOG.debug("{}: follower: {}, matchIndex set to {}, nextIndex set to {}",
+                                logName(), followerId, followerLogInformation.getMatchIndex(),
+                                followerLogInformation.getNextIndex());
 
                     if (mapFollowerToSnapshot.isEmpty()) {
                         // once there are no pending followers receiving snapshots
@@ -380,7 +379,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
                 }
             } else {
                 LOG.info("{}: InstallSnapshotReply received sending snapshot chunk failed, Will retry, Chunk: {}",
-                        context.getId(), reply.getChunkIndex());
+                        logName(), reply.getChunkIndex());
 
                 followerToSnapshot.markSendStatus(false);
             }
@@ -394,7 +393,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
 
         } else {
             LOG.error("{}: Chunk index {} in InstallSnapshotReply from follower {} does not match expected index {}",
-                    context.getId(), reply.getChunkIndex(), followerId,
+                    logName(), reply.getChunkIndex(), followerId,
                     followerToSnapshot.getChunkIndex());
 
             if(reply.getChunkIndex() == INVALID_CHUNK_INDEX){
@@ -408,9 +407,8 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
     private void replicate(Replicate replicate) {
         long logIndex = replicate.getReplicatedLogEntry().getIndex();
 
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: Replicate message {}", context.getId(), logIndex);
-        }
+        LOG.debug("{}: Replicate message: identifier: {}, logIndex: {}", logName(),
+                replicate.getIdentifier(), logIndex);
 
         // Create a tracker entry we will use this later to notify the
         // client actor
@@ -424,11 +422,11 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             context.setCommitIndex(logIndex);
             applyLogToStateMachine(logIndex);
         } else {
-            sendAppendEntries(0);
+            sendAppendEntries(0, false);
         }
     }
 
-    private void sendAppendEntries(long timeSinceLastActivityInterval) {
+    private void sendAppendEntries(long timeSinceLastActivityInterval, boolean isHeartbeat) {
         // Send an AppendEntries to all followers
         for (Entry<String, FollowerLogInformation> e : followerToLog.entrySet()) {
             final String followerId = e.getKey();
@@ -436,7 +434,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             // This checks helps not to send a repeat message to the follower
             if(!followerLogInformation.isFollowerActive() ||
                     followerLogInformation.timeSinceLastActivity() >= timeSinceLastActivityInterval) {
-                sendUpdatesToFollower(followerId, followerLogInformation, true);
+                sendUpdatesToFollower(followerId, followerLogInformation, true, isHeartbeat);
             }
         }
     }
@@ -449,7 +447,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
      */
 
     private void sendUpdatesToFollower(String followerId, FollowerLogInformation followerLogInformation,
-                                          boolean sendHeartbeat) {
+                                       boolean sendHeartbeat, boolean isHeartbeat) {
 
         ActorSelection followerActor = context.getPeerActorSelection(followerId);
         if (followerActor != null) {
@@ -468,32 +466,41 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             } else {
                 long leaderLastIndex = context.getReplicatedLog().lastIndex();
                 long leaderSnapShotIndex = context.getReplicatedLog().getSnapshotIndex();
-                if (isFollowerActive &&
-                    context.getReplicatedLog().isPresent(followerNextIndex)) {
+
+                if(!isHeartbeat || LOG.isTraceEnabled()) {
+                    LOG.debug("{}: Checking sendAppendEntries for follower {}, leaderLastIndex: {}, leaderSnapShotIndex: {}",
+                            logName(), followerId, leaderLastIndex, leaderSnapShotIndex);
+                }
+
+                if (isFollowerActive && context.getReplicatedLog().isPresent(followerNextIndex)) {
+
+                    LOG.debug("{}: sendAppendEntries: {} is present for follower {}", logName(),
+                            followerNextIndex, followerId);
+
                     // FIXME : Sending one entry at a time
                     final List<ReplicatedLogEntry> entries = context.getReplicatedLog().getFrom(followerNextIndex, 1);
 
                     sendAppendEntriesToFollower(followerActor, followerNextIndex, entries, followerId);
 
                 } else if (isFollowerActive && followerNextIndex >= 0 &&
-                    leaderLastIndex >= followerNextIndex) {
+                    leaderLastIndex > followerNextIndex && !context.isSnapshotCaptureInitiated()) {
                     // if the followers next index is not present in the leaders log, and
                     // if the follower is just not starting and if leader's index is more than followers index
                     // then snapshot should be sent
 
                     if (LOG.isDebugEnabled()) {
-                        LOG.debug("InitiateInstallSnapshot to follower:{}," +
-                                "follower-nextIndex:{}, leader-snapshot-index:{},  " +
-                                "leader-last-index:{}", followerId,
-                            followerNextIndex, leaderSnapShotIndex, leaderLastIndex
-                        );
+                        LOG.debug(String.format("%s: InitiateInstallSnapshot to follower: %s," +
+                                    "follower-nextIndex: %d, leader-snapshot-index: %d,  " +
+                                    "leader-last-index: %d", logName(), followerId,
+                                    followerNextIndex, leaderSnapShotIndex, leaderLastIndex));
                     }
-                    actor().tell(new InitiateInstallSnapshot(), actor());
 
                     // Send heartbeat to follower whenever install snapshot is initiated.
                     sendAppendEntriesToFollower(followerActor, followerLogInformation.getNextIndex(),
                             Collections.<ReplicatedLogEntry>emptyList(), followerId);
 
+                    initiateCaptureSnapshot(followerId, followerNextIndex);
+
                 } else if(sendHeartbeat) {
                     //we send an AppendEntries, even if the follower is inactive
                     // in-order to update the followers timestamp, in case it becomes active again
@@ -510,10 +517,10 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
         AppendEntries appendEntries = new AppendEntries(currentTerm(), context.getId(),
             prevLogIndex(followerNextIndex),
             prevLogTerm(followerNextIndex), entries,
-            context.getCommitIndex(), replicatedToAllIndex);
+            context.getCommitIndex(), super.getReplicatedToAllIndex());
 
-        if(!entries.isEmpty()) {
-            LOG.debug("{}: Sending AppendEntries to follower {}: {}", context.getId(), followerId,
+        if(!entries.isEmpty() || LOG.isTraceEnabled()) {
+            LOG.debug("{}: Sending AppendEntries to follower {}: {}", logName(), followerId,
                     appendEntries);
         }
 
@@ -521,78 +528,60 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
     }
 
     /**
-     * An installSnapshot is scheduled at a interval that is a multiple of
-     * a HEARTBEAT_INTERVAL. This is to avoid the need to check for installing
-     * snapshots at every heartbeat.
-     *
      * Install Snapshot works as follows
-     * 1. Leader sends a InitiateInstallSnapshot message to self
-     * 2. Leader then initiates the capture snapshot by sending a CaptureSnapshot message to actor
-     * 3. RaftActor on receipt of the CaptureSnapshotReply (from Shard), stores the received snapshot in the replicated log
+     * 1. Leader initiates the capture snapshot by sending a CaptureSnapshot message to actor
+     * 2. RaftActor on receipt of the CaptureSnapshotReply (from Shard), stores the received snapshot in the replicated log
      * and makes a call to Leader's handleMessage , with SendInstallSnapshot message.
-     * 4. Leader , picks the snapshot from im-mem ReplicatedLog and sends it in chunks to the Follower
-     * 5. On complete, Follower sends back a InstallSnapshotReply.
-     * 6. On receipt of the InstallSnapshotReply for the last chunk, Leader marks the install complete for that follower
+     * 3. Leader , picks the snapshot from im-mem ReplicatedLog and sends it in chunks to the Follower
+     * 4. On complete, Follower sends back a InstallSnapshotReply.
+     * 5. On receipt of the InstallSnapshotReply for the last chunk, Leader marks the install complete for that follower
      * and replenishes the memory by deleting the snapshot in Replicated log.
-     *
+     * 6. If another follower requires a snapshot and a snapshot has been collected (via CaptureSnapshotReply)
+     * then send the existing snapshot in chunks to the follower.
+     * @param followerId
+     * @param followerNextIndex
      */
-    private void installSnapshotIfNeeded() {
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: installSnapshotIfNeeded, followers {}", context.getId(), followerToLog.keySet());
-        }
-
-        for (Entry<String, FollowerLogInformation> e : followerToLog.entrySet()) {
-            final ActorSelection followerActor = context.getPeerActorSelection(e.getKey());
-
-            if (followerActor != null) {
-                long nextIndex = e.getValue().getNextIndex();
-
-                if (!context.getReplicatedLog().isPresent(nextIndex) &&
-                        context.getReplicatedLog().isInSnapshot(nextIndex)) {
-                    LOG.info("{}: {} follower needs a snapshot install", context.getId(), e.getKey());
-                    if (snapshot.isPresent()) {
-                        // if a snapshot is present in the memory, most likely another install is in progress
-                        // no need to capture snapshot
-                        sendSnapshotChunk(followerActor, e.getKey());
-
-                    } else if (!context.isSnapshotCaptureInitiated()) {
-                        initiateCaptureSnapshot();
-                        //we just need 1 follower who would need snapshot to be installed.
-                        // when we have the snapshot captured, we would again check (in SendInstallSnapshot)
-                        // who needs an install and send to all who need
-                        break;
-                    }
+    private void initiateCaptureSnapshot(String followerId, long followerNextIndex) {
+        if (!context.getReplicatedLog().isPresent(followerNextIndex) &&
+                context.getReplicatedLog().isInSnapshot(followerNextIndex)) {
 
+            if (snapshot.isPresent()) {
+                // if a snapshot is present in the memory, most likely another install is in progress
+                // no need to capture snapshot.
+                // This could happen if another follower needs an install when one is going on.
+                final ActorSelection followerActor = context.getPeerActorSelection(followerId);
+                sendSnapshotChunk(followerActor, followerId);
+
+            } else if (!context.isSnapshotCaptureInitiated()) {
+
+                LOG.info("{}: Initiating Snapshot Capture to Install Snapshot, Leader:{}", logName(), getLeaderId());
+                ReplicatedLogEntry lastAppliedEntry = context.getReplicatedLog().get(context.getLastApplied());
+                long lastAppliedIndex = -1;
+                long lastAppliedTerm = -1;
+
+                if (lastAppliedEntry != null) {
+                    lastAppliedIndex = lastAppliedEntry.getIndex();
+                    lastAppliedTerm = lastAppliedEntry.getTerm();
+                } else if (context.getReplicatedLog().getSnapshotIndex() > -1) {
+                    lastAppliedIndex = context.getReplicatedLog().getSnapshotIndex();
+                    lastAppliedTerm = context.getReplicatedLog().getSnapshotTerm();
                 }
+
+                boolean isInstallSnapshotInitiated = true;
+                long replicatedToAllIndex = super.getReplicatedToAllIndex();
+                ReplicatedLogEntry replicatedToAllEntry = context.getReplicatedLog().get(replicatedToAllIndex);
+                actor().tell(new CaptureSnapshot(lastIndex(), lastTerm(), lastAppliedIndex, lastAppliedTerm,
+                    (replicatedToAllEntry != null ? replicatedToAllEntry.getIndex() : -1),
+                    (replicatedToAllEntry != null ? replicatedToAllEntry.getTerm() : -1),
+                    isInstallSnapshotInitiated), actor());
+                context.setSnapshotCaptureInitiated(true);
             }
         }
     }
 
-    // on every install snapshot, we try to capture the snapshot.
-    // Once a capture is going on, another one issued will get ignored by RaftActor.
-    private void initiateCaptureSnapshot() {
-        LOG.info("{}: Initiating Snapshot Capture to Install Snapshot, Leader:{}", context.getId(), getLeaderId());
-        ReplicatedLogEntry lastAppliedEntry = context.getReplicatedLog().get(context.getLastApplied());
-        long lastAppliedIndex = -1;
-        long lastAppliedTerm = -1;
-
-        if (lastAppliedEntry != null) {
-            lastAppliedIndex = lastAppliedEntry.getIndex();
-            lastAppliedTerm = lastAppliedEntry.getTerm();
-        } else if (context.getReplicatedLog().getSnapshotIndex() > -1)  {
-            lastAppliedIndex = context.getReplicatedLog().getSnapshotIndex();
-            lastAppliedTerm = context.getReplicatedLog().getSnapshotTerm();
-        }
-
-        boolean isInstallSnapshotInitiated = true;
-        actor().tell(new CaptureSnapshot(lastIndex(), lastTerm(),
-                lastAppliedIndex, lastAppliedTerm, isInstallSnapshotInitiated),
-            actor());
-        context.setSnapshotCaptureInitiated(true);
-    }
-
 
     private void sendInstallSnapshot() {
+        LOG.debug("{}: sendInstallSnapshot", logName());
         for (Entry<String, FollowerLogInformation> e : followerToLog.entrySet()) {
             ActorSelection followerActor = context.getPeerActorSelection(e.getKey());
 
@@ -625,19 +614,19 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
                         context.getReplicatedLog().getSnapshotIndex(),
                         context.getReplicatedLog().getSnapshotTerm(),
                         nextSnapshotChunk,
-                            followerToSnapshot.incrementChunkIndex(),
-                            followerToSnapshot.getTotalChunks(),
+                        followerToSnapshot.incrementChunkIndex(),
+                        followerToSnapshot.getTotalChunks(),
                         Optional.of(followerToSnapshot.getLastChunkHashCode())
                     ).toSerializable(),
                     actor()
                 );
                 LOG.info("{}: InstallSnapshot sent to follower {}, Chunk: {}/{}",
-                        context.getId(), followerActor.path(),
+                        logName(), followerActor.path(),
                         followerToSnapshot.getChunkIndex(),
                         followerToSnapshot.getTotalChunks());
             }
         } catch (IOException e) {
-            LOG.error("{}: InstallSnapshot failed for Leader.", context.getId(), e);
+            LOG.error("{}: InstallSnapshot failed for Leader.", logName(), e);
         }
     }
 
@@ -652,15 +641,16 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
             mapFollowerToSnapshot.put(followerId, followerToSnapshot);
         }
         ByteString nextChunk = followerToSnapshot.getNextChunk();
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("{}: Leader's snapshot nextChunk size:{}", context.getId(), nextChunk.size());
-        }
+
+        LOG.debug("{}: next snapshot chunk size for follower {}: {}", logName(), followerId, nextChunk.size());
+
         return nextChunk;
     }
 
     private void sendHeartBeat() {
         if (!followerToLog.isEmpty()) {
-            sendAppendEntries(context.getConfigParams().getHeartBeatInterval().toMillis());
+            LOG.trace("{}: Sending heartbeat", logName());
+            sendAppendEntries(context.getConfigParams().getHeartBeatInterval().toMillis(), true);
         }
     }
 
@@ -735,7 +725,7 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
                 ((size % context.getConfigParams().getSnapshotChunkSize()) > 0 ? 1 : 0);
             if(LOG.isDebugEnabled()) {
                 LOG.debug("{}: Snapshot {} bytes, total chunks to send:{}",
-                        context.getId(), size, totalChunks);
+                        logName(), size, totalChunks);
             }
             replyReceivedForOffset = -1;
             chunkIndex = AbstractLeader.FIRST_CHUNK_INDEX;
@@ -803,10 +793,10 @@ public abstract class AbstractLeader extends AbstractRaftActorBehavior {
                 }
             }
 
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: Next chunk: length={}, offset={},size={}", context.getId(),
+
+            LOG.debug("{}: Next chunk: length={}, offset={},size={}", logName(),
                     snapshotLength, start, size);
-            }
+
             ByteString substring = getSnapshotBytes().substring(start, start + size);
             nextChunkHashCode = substring.hashCode();
             return substring;
index 075b2873e45332364c09aee83c49e6b23e40780c..0b0b4c7cd642480f92dd600a4f8f10be07977dc4 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Random;
 import java.util.concurrent.TimeUnit;
 import org.opendaylight.controller.cluster.raft.ClientRequestTracker;
 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.base.messages.ApplyLogEntries;
@@ -58,10 +59,37 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      */
     protected String leaderId = null;
 
+    private long replicatedToAllIndex = -1;
 
-    protected AbstractRaftActorBehavior(RaftActorContext context) {
+    private final String logName;
+
+    private final RaftState state;
+
+    protected AbstractRaftActorBehavior(RaftActorContext context, RaftState state) {
         this.context = context;
+        this.state = state;
         this.LOG = context.getLogger();
+
+        logName = String.format("%s (%s)", context.getId(), state);
+    }
+
+    @Override
+    public RaftState state() {
+        return state;
+    }
+
+    public String logName() {
+        return logName;
+    }
+
+    @Override
+    public void setReplicatedToAllIndex(long replicatedToAllIndex) {
+        this.replicatedToAllIndex = replicatedToAllIndex;
+    }
+
+    @Override
+    public long getReplicatedToAllIndex() {
+        return replicatedToAllIndex;
     }
 
     /**
@@ -95,7 +123,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
         if (appendEntries.getTerm() < currentTerm()) {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("{}: Cannot append entries because sender term {} is less than {}",
-                        context.getId(), appendEntries.getTerm(), currentTerm());
+                        logName(), appendEntries.getTerm(), currentTerm());
             }
 
             sender.tell(
@@ -132,12 +160,9 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      * @param requestVote
      * @return
      */
-    protected RaftActorBehavior requestVote(ActorRef sender,
-        RequestVote requestVote) {
+    protected RaftActorBehavior requestVote(ActorRef sender, RequestVote requestVote) {
 
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: Received {}", context.getId(), requestVote);
-        }
+        LOG.debug("{}: In requestVote:  {}", logName(), requestVote);
 
         boolean grantVote = false;
 
@@ -173,7 +198,11 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
             }
         }
 
-        sender.tell(new RequestVoteReply(currentTerm(), grantVote), actor());
+        RequestVoteReply reply = new RequestVoteReply(currentTerm(), grantVote);
+
+        LOG.debug("{}: requestVote returning: {}", logName(), reply);
+
+        sender.tell(reply, actor());
 
         return this;
     }
@@ -351,12 +380,12 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
                 // around as the rest wont be present either
                 LOG.warn(
                         "{}: Missing index {} from log. Cannot apply state. Ignoring {} to {}",
-                        context.getId(), i, i, index);
+                        logName(), i, i, index);
                 break;
             }
         }
         if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: Setting last applied to {}", context.getId(), newLastApplied);
+            LOG.debug("{}: Setting last applied to {}", logName(), newLastApplied);
         }
         context.setLastApplied(newLastApplied);
 
@@ -390,11 +419,11 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
     }
 
     protected RaftActorBehavior switchBehavior(RaftActorBehavior behavior) {
-        LOG.info("{} :- Switching from behavior {} to {}", context.getId(), this.state(), behavior.state());
+        LOG.info("{} :- Switching from behavior {} to {}", logName(), this.state(), behavior.state());
         try {
             close();
         } catch (Exception e) {
-            LOG.error("{}: Failed to close behavior : {}", context.getId(), this.state(), e);
+            LOG.error("{}: Failed to close behavior : {}", logName(), this.state(), e);
         }
 
         return behavior;
@@ -423,17 +452,28 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
 
     }
 
-    protected long fakeSnapshot(final long minReplicatedToAllIndex, final long currentReplicatedIndex) {
 
+    /**
+     * Performs a snapshot with no capture on the replicated log.
+     * It clears the log from the supplied index or last-applied-1 which ever is minimum.
+     *
+     * @param snapshotCapturedIndex
+     */
+    protected void performSnapshotWithoutCapture(final long snapshotCapturedIndex) {
         //  we would want to keep the lastApplied as its used while capturing snapshots
-        long tempMin = Math.min(minReplicatedToAllIndex,
-                (context.getLastApplied() > -1 ? context.getLastApplied() - 1 : -1));
+        long lastApplied = context.getLastApplied();
+        long tempMin = Math.min(snapshotCapturedIndex, (lastApplied > -1 ? lastApplied - 1 : -1));
 
         if (tempMin > -1 && context.getReplicatedLog().isPresent(tempMin))  {
-            context.getReplicatedLog().snapshotPreCommit(tempMin, context.getTermInformation().getCurrentTerm());
+            LOG.debug("{}: fakeSnapshot purging log to {} for term {}", logName(), tempMin,
+                    context.getTermInformation().getCurrentTerm());
+
+            //use the term of the temp-min, since we check for isPresent, entry will not be null
+            ReplicatedLogEntry entry = context.getReplicatedLog().get(tempMin);
+            context.getReplicatedLog().snapshotPreCommit(tempMin, entry.getTerm());
             context.getReplicatedLog().snapshotCommit();
-            return tempMin;
+            setReplicatedToAllIndex(tempMin);
         }
-        return currentReplicatedIndex;
     }
+
 }
index 09ffe056c3e94fcd4592f8f44f4e29123967f918..b36c41abf262b8c24d05f354091f7c4ec92a0827 100644 (file)
@@ -47,12 +47,12 @@ public class Candidate extends AbstractRaftActorBehavior {
     private final Set<String> peers;
 
     public Candidate(RaftActorContext context) {
-        super(context);
+        super(context, RaftState.Candidate);
 
         peers = context.getPeerAddresses().keySet();
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: Election: Candidate has following peers: {}", context.getId(), peers);
+            LOG.debug("{}: Election: Candidate has following peers: {}", logName(), peers);
         }
 
         votesRequired = getMajorityVoteCount(peers.size());
@@ -65,7 +65,7 @@ public class Candidate extends AbstractRaftActorBehavior {
         AppendEntries appendEntries) {
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: handleAppendEntries: {}", context.getId(), appendEntries);
+            LOG.debug("{}: handleAppendEntries: {}", logName(), appendEntries);
         }
 
         return this;
@@ -78,7 +78,10 @@ public class Candidate extends AbstractRaftActorBehavior {
     }
 
     @Override protected RaftActorBehavior handleRequestVoteReply(ActorRef sender,
-        RequestVoteReply requestVoteReply) {
+            RequestVoteReply requestVoteReply) {
+
+        LOG.debug("{}: handleRequestVoteReply: {}, current voteCount: {}", logName(), requestVoteReply,
+                voteCount);
 
         if (requestVoteReply.isVoteGranted()) {
             voteCount++;
@@ -91,10 +94,6 @@ public class Candidate extends AbstractRaftActorBehavior {
         return this;
     }
 
-    @Override public RaftState state() {
-        return RaftState.Candidate;
-    }
-
     @Override
     public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
 
@@ -105,7 +104,7 @@ public class Candidate extends AbstractRaftActorBehavior {
             RaftRPC rpc = (RaftRPC) message;
 
             if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: RaftRPC message received {} my term is {}", context.getId(), rpc,
+                LOG.debug("{}: RaftRPC message received {}, my term is {}", logName(), rpc,
                         context.getTermInformation().getCurrentTerm());
             }
 
@@ -120,6 +119,8 @@ public class Candidate extends AbstractRaftActorBehavior {
         }
 
         if (message instanceof ElectionTimeout) {
+            LOG.debug("{}: Received ElectionTimeout", logName());
+
             if (votesRequired == 0) {
                 // If there are no peers then we should be a Leader
                 // We wait for the election timeout to occur before declare
@@ -146,12 +147,10 @@ public class Candidate extends AbstractRaftActorBehavior {
 
         // Increment the election term and vote for self
         long currentTerm = context.getTermInformation().getCurrentTerm();
-        context.getTermInformation().updateAndPersist(currentTerm + 1,
-            context.getId());
+        long newTerm = currentTerm + 1;
+        context.getTermInformation().updateAndPersist(newTerm, context.getId());
 
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: Starting new term {}", context.getId(), (currentTerm + 1));
-        }
+        LOG.debug("{}: Starting new term {}", logName(), newTerm);
 
         // Request for a vote
         // TODO: Retry request for vote if replies do not arrive in a reasonable
@@ -159,17 +158,17 @@ public class Candidate extends AbstractRaftActorBehavior {
         for (String peerId : peers) {
             ActorSelection peerActor = context.getPeerActorSelection(peerId);
             if(peerActor != null) {
-                peerActor.tell(new RequestVote(
+                RequestVote requestVote = new RequestVote(
                         context.getTermInformation().getCurrentTerm(),
                         context.getId(),
                         context.getReplicatedLog().lastIndex(),
-                        context.getReplicatedLog().lastTerm()),
-                    context.getActor()
-                );
-            }
-        }
+                        context.getReplicatedLog().lastTerm());
 
+                LOG.debug("{}: Sending {} to peer {}", logName(), requestVote, peerId);
 
+                peerActor.tell(requestVote, context.getActor());
+            }
+        }
     }
 
     @Override public void close() throws Exception {
index 8a0788702d81f3dfe04d713bcc99e527273c82d2..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;
@@ -40,7 +39,7 @@ public class Follower extends AbstractRaftActorBehavior {
     private SnapshotTracker snapshotTracker = null;
 
     public Follower(RaftActorContext context) {
-        super(context);
+        super(context, RaftState.Follower);
 
         scheduleElection(electionDuration());
     }
@@ -75,10 +74,11 @@ public class Follower extends AbstractRaftActorBehavior {
     @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender,
                                                               AppendEntries appendEntries) {
 
-        if(appendEntries.getEntries() != null && appendEntries.getEntries().size() > 0) {
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: handleAppendEntries: {}", context.getId(), appendEntries);
-            }
+        int numLogEntries = appendEntries.getEntries() != null ? appendEntries.getEntries().size() : 0;
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("{}: handleAppendEntries: {}", logName(), appendEntries);
+        } else if(LOG.isDebugEnabled() && numLogEntries > 0) {
+            LOG.debug("{}: handleAppendEntries: {}", logName(), appendEntries);
         }
 
         // TODO : Refactor this method into a bunch of smaller methods
@@ -101,44 +101,31 @@ public class Follower extends AbstractRaftActorBehavior {
         boolean outOfSync = true;
 
         // First check if the logs are in sync or not
-        if (lastIndex() == -1
-                && appendEntries.getPrevLogIndex() != -1) {
+        long lastIndex = lastIndex();
+        if (lastIndex == -1 && appendEntries.getPrevLogIndex() != -1) {
 
             // The follower's log is out of sync because the leader does have
             // an entry at prevLogIndex and this follower has no entries in
             // it's log.
 
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: The followers log is empty and the senders prevLogIndex is {}",
-                        context.getId(), appendEntries.getPrevLogIndex());
-            }
-
-        } else if (lastIndex() > -1
-                && appendEntries.getPrevLogIndex() != -1
-                && !prevEntryPresent) {
+            LOG.debug("{}: The followers log is empty and the senders prevLogIndex is {}",
+                        logName(), appendEntries.getPrevLogIndex());
+        } else if (lastIndex > -1 && appendEntries.getPrevLogIndex() != -1 && !prevEntryPresent) {
 
             // The follower's log is out of sync because the Leader's
             // prevLogIndex entry was not found in it's log
 
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: The log is not empty but the prevLogIndex {} was not found in it",
-                        context.getId(), appendEntries.getPrevLogIndex());
-            }
-
-        } else if (lastIndex() > -1
-                && prevEntryPresent
-                && prevLogTerm != appendEntries.getPrevLogTerm()) {
+            LOG.debug("{}: The log is not empty but the prevLogIndex {} was not found in it",
+                        logName(), appendEntries.getPrevLogIndex());
+        } else if (lastIndex > -1 && prevEntryPresent && prevLogTerm != appendEntries.getPrevLogTerm()) {
 
             // The follower's log is out of sync because the Leader's
             // prevLogIndex entry does exist in the follower's log but it has
             // a different term in it
 
-            if (LOG.isDebugEnabled()) {
-                LOG.debug(
-                        "{}: Cannot append entries because previous entry term {}  is not equal to append entries prevLogTerm {}"
-                        , context.getId(), prevLogTerm
-                        , appendEntries.getPrevLogTerm());
-            }
+            LOG.debug(
+                "{}: Cannot append entries because previous entry term {}  is not equal to append entries prevLogTerm {}",
+                 logName(), prevLogTerm, appendEntries.getPrevLogTerm());
         } else {
             outOfSync = false;
         }
@@ -146,25 +133,19 @@ public class Follower extends AbstractRaftActorBehavior {
         if (outOfSync) {
             // We found that the log was out of sync so just send a negative
             // reply and return
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: Follower ({}) is out-of-sync, " +
-                        "so sending negative reply, lastIndex():{}, lastTerm():{}",
-                        context.getId(), context.getId(), lastIndex(), lastTerm()
-                );
-            }
-            sender.tell(
-                new AppendEntriesReply(context.getId(), currentTerm(), false,
-                    lastIndex(), lastTerm()), actor()
-            );
+
+            LOG.debug("{}: Follower is out-of-sync, so sending negative reply, lastIndex: {}, lastTerm: {}",
+                        logName(), lastIndex, lastTerm());
+
+            sender.tell(new AppendEntriesReply(context.getId(), currentTerm(), false, lastIndex,
+                    lastTerm()), actor());
             return this;
         }
 
-        if (appendEntries.getEntries() != null
-            && appendEntries.getEntries().size() > 0) {
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: Number of entries to be appended = {}", context.getId(),
+        if (appendEntries.getEntries() != null && appendEntries.getEntries().size() > 0) {
+
+            LOG.debug("{}: Number of entries to be appended = {}", logName(),
                         appendEntries.getEntries().size());
-            }
 
             // 3. If an existing entry conflicts with a new one (same index
             // but different terms), delete the existing entry and all that
@@ -182,80 +163,75 @@ public class Follower extends AbstractRaftActorBehavior {
                         break;
                     }
 
-                    if (newEntry.getTerm() == matchEntry
-                        .getTerm()) {
+                    if (newEntry.getTerm() == matchEntry.getTerm()) {
                         continue;
                     }
 
-                    if(LOG.isDebugEnabled()) {
-                        LOG.debug("{}: Removing entries from log starting at {}", context.getId(),
+                    LOG.debug("{}: Removing entries from log starting at {}", logName(),
                                 matchEntry.getIndex());
-                    }
 
                     // Entries do not match so remove all subsequent entries
-                    context.getReplicatedLog()
-                        .removeFromAndPersist(matchEntry.getIndex());
+                    context.getReplicatedLog().removeFromAndPersist(matchEntry.getIndex());
                     break;
                 }
             }
 
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: After cleanup entries to be added from = {}", context.getId(),
-                        (addEntriesFrom + lastIndex()));
-            }
+            lastIndex = lastIndex();
+            LOG.debug("{}: After cleanup entries to be added from = {}", logName(),
+                        (addEntriesFrom + lastIndex));
 
             // 4. Append any new entries not already in the log
-            for (int i = addEntriesFrom;
-                 i < appendEntries.getEntries().size(); i++) {
+            for (int i = addEntriesFrom; i < appendEntries.getEntries().size(); i++) {
+                ReplicatedLogEntry entry = appendEntries.getEntries().get(i);
 
-                if(LOG.isDebugEnabled()) {
-                    LOG.debug("{}: Append entry to log {}", context.getId(),
-                            appendEntries.getEntries().get(i).getData());
-                }
-                context.getReplicatedLog().appendAndPersist(appendEntries.getEntries().get(i));
-            }
+                LOG.debug("{}: Append entry to log {}", logName(), entry.getData());
 
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: Log size is now {}", context.getId(), context.getReplicatedLog().size());
+                context.getReplicatedLog().appendAndPersist(entry);
             }
-        }
 
+            LOG.debug("{}: Log size is now {}", logName(), context.getReplicatedLog().size());
+        }
 
         // 5. If leaderCommit > commitIndex, set commitIndex =
         // min(leaderCommit, index of last new entry)
 
+        lastIndex = lastIndex();
         long prevCommitIndex = context.getCommitIndex();
 
-        context.setCommitIndex(Math.min(appendEntries.getLeaderCommit(),
-            context.getReplicatedLog().lastIndex()));
+        context.setCommitIndex(Math.min(appendEntries.getLeaderCommit(), lastIndex));
 
         if (prevCommitIndex != context.getCommitIndex()) {
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("{}: Commit index set to {}", context.getId(), context.getCommitIndex());
-            }
+            LOG.debug("{}: Commit index set to {}", logName(), context.getCommitIndex());
         }
 
         // If commitIndex > lastApplied: increment lastApplied, apply
         // log[lastApplied] to state machine (§5.3)
         // check if there are any entries to be applied. last-applied can be equal to last-index
         if (appendEntries.getLeaderCommit() > context.getLastApplied() &&
-            context.getLastApplied() < lastIndex()) {
+            context.getLastApplied() < lastIndex) {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("{}: applyLogToStateMachine, " +
-                        "appendEntries.getLeaderCommit():{}," +
-                        "context.getLastApplied():{}, lastIndex():{}", context.getId(),
-                    appendEntries.getLeaderCommit(), context.getLastApplied(), lastIndex()
-                );
+                        "appendEntries.getLeaderCommit(): {}," +
+                        "context.getLastApplied(): {}, lastIndex(): {}", logName(),
+                    appendEntries.getLeaderCommit(), context.getLastApplied(), lastIndex);
             }
 
             applyLogToStateMachine(appendEntries.getLeaderCommit());
         }
 
-        sender.tell(new AppendEntriesReply(context.getId(), currentTerm(), true,
-            lastIndex(), lastTerm()), actor());
+        AppendEntriesReply reply = new AppendEntriesReply(context.getId(), currentTerm(), true,
+            lastIndex, lastTerm());
+
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("{}: handleAppendEntries returning : {}", logName(), reply);
+        } else if(LOG.isDebugEnabled() && numLogEntries > 0) {
+            LOG.debug("{}: handleAppendEntries returning : {}", logName(), reply);
+        }
+
+        sender.tell(reply, actor());
 
         if (!context.isSnapshotCaptureInitiated()) {
-            fakeSnapshot(appendEntries.getReplicatedToAllIndex(), appendEntries.getReplicatedToAllIndex());
+            super.performSnapshotWithoutCapture(appendEntries.getReplicatedToAllIndex());
         }
 
         return this;
@@ -271,10 +247,6 @@ public class Follower extends AbstractRaftActorBehavior {
         return this;
     }
 
-    @Override public RaftState state() {
-        return RaftState.Follower;
-    }
-
     @Override public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
 
         Object message = fromSerializableMessage(originalMessage);
@@ -285,11 +257,15 @@ public class Follower extends AbstractRaftActorBehavior {
             // set currentTerm = T, convert to follower (§5.1)
             // This applies to all RPC messages and responses
             if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()) {
+                LOG.debug("{}: Term {} in \"{}\" message is greater than follower's term {} - updating term",
+                        logName(), rpc.getTerm(), rpc, context.getTermInformation().getCurrentTerm());
+
                 context.getTermInformation().updateAndPersist(rpc.getTerm(), null);
             }
         }
 
         if (message instanceof ElectionTimeout) {
+            LOG.debug("{}: Received ElectionTimeout - switching to Candidate", logName());
             return switchBehavior(new Candidate(context));
 
         } else if (message instanceof InstallSnapshot) {
@@ -304,12 +280,10 @@ public class Follower extends AbstractRaftActorBehavior {
 
     private void handleInstallSnapshot(ActorRef sender, InstallSnapshot installSnapshot) {
 
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: InstallSnapshot received by follower " +
-                    "datasize:{} , Chunk:{}/{}", context.getId(), installSnapshot.getData().size(),
-                installSnapshot.getChunkIndex(), installSnapshot.getTotalChunks()
-            );
-        }
+
+        LOG.debug("{}: InstallSnapshot received from leader {}, datasize: {} , Chunk: {}/{}",
+                    logName(), installSnapshot.getLeaderId(), installSnapshot.getData().size(),
+                    installSnapshot.getChunkIndex(), installSnapshot.getTotalChunks());
 
         if(snapshotTracker == null){
             snapshotTracker = new SnapshotTracker(LOG, installSnapshot.getTotalChunks());
@@ -331,18 +305,23 @@ public class Follower extends AbstractRaftActorBehavior {
 
             }
 
-            sender.tell(new InstallSnapshotReply(
-                    currentTerm(), context.getId(), installSnapshot.getChunkIndex(),
-                    true), actor());
+            InstallSnapshotReply reply = new InstallSnapshotReply(
+                    currentTerm(), context.getId(), installSnapshot.getChunkIndex(), true);
+
+            LOG.debug("{}: handleInstallSnapshot returning: {}", logName(), reply);
+
+            sender.tell(reply, actor());
 
         } catch (SnapshotTracker.InvalidChunkException e) {
+            LOG.debug("{}: Exception in InstallSnapshot of follower", logName(), e);
 
             sender.tell(new InstallSnapshotReply(currentTerm(), context.getId(),
                     -1, false), actor());
             snapshotTracker = null;
 
         } catch (Exception e){
-            LOG.error("{}: Exception in InstallSnapshot of follower", context.getId(), e);
+            LOG.error("{}: Exception in InstallSnapshot of follower", logName(), e);
+
             //send reply with success as false. The chunk will be sent again on failure
             sender.tell(new InstallSnapshotReply(currentTerm(), context.getId(),
                     installSnapshot.getChunkIndex(), false), actor());
@@ -350,14 +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 064cd8b88c8b68152f04cdc25378c792eb263a7b..b766e0ce39fe9be1b847f54c625c802d036a7a0a 100644 (file)
@@ -50,4 +50,16 @@ public interface RaftActorBehavior extends AutoCloseable{
      * @return
      */
     String getLeaderId();
+
+    /**
+     * setting the index of the log entry which is replicated to all nodes
+     * @param replicatedToAllIndex
+     */
+    void setReplicatedToAllIndex(long replicatedToAllIndex);
+
+    /**
+     * getting the index of the log entry which is replicated to all nodes
+     * @return
+     */
+    long getReplicatedToAllIndex();
 }
index 97bcd6a708b7c8f11646b026e7e1653a2713ff40..d2ea0c50cd6203fd6b142793612e4e0546000185 100644 (file)
@@ -110,19 +110,15 @@ public class AppendEntries extends AbstractRaftRPC {
         return replicatedToAllIndex;
     }
 
+
     @Override
     public String toString() {
-        final StringBuilder sb =
-            new StringBuilder("AppendEntries{");
-        sb.append("term=").append(getTerm());
-        sb.append("leaderId='").append(leaderId).append('\'');
-        sb.append(", prevLogIndex=").append(prevLogIndex);
-        sb.append(", prevLogTerm=").append(prevLogTerm);
-        sb.append(", entries=").append(entries);
-        sb.append(", leaderCommit=").append(leaderCommit);
-        sb.append(", replicatedToAllIndex=").append(replicatedToAllIndex);
-        sb.append('}');
-        return sb.toString();
+        StringBuilder builder = new StringBuilder();
+        builder.append("AppendEntries [term=").append(term).append(", leaderId=").append(leaderId)
+                .append(", prevLogIndex=").append(prevLogIndex).append(", prevLogTerm=").append(prevLogTerm)
+                .append(", entries=").append(entries).append(", leaderCommit=").append(leaderCommit)
+                .append(", replicatedToAllIndex=").append(replicatedToAllIndex).append("]");
+        return builder.toString();
     }
 
     public <T extends Object> Object toSerializable() {
index 32ed85b281fee0feb4b0533c0b72cb5ade40093a..01fef006a922a5b69290df2eaf19a4017ead65d9 100644 (file)
@@ -59,15 +59,12 @@ public class AppendEntriesReply extends AbstractRaftRPC {
         return followerId;
     }
 
-    @Override public String toString() {
-        final StringBuilder sb =
-            new StringBuilder("AppendEntriesReply{");
-        sb.append("term=").append(term);
-        sb.append(", success=").append(success);
-        sb.append(", logLastIndex=").append(logLastIndex);
-        sb.append(", logLastTerm=").append(logLastTerm);
-        sb.append(", followerId='").append(followerId).append('\'');
-        sb.append('}');
-        return sb.toString();
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("AppendEntriesReply [term=").append(term).append(", success=").append(success)
+                .append(", logLastIndex=").append(logLastIndex).append(", logLastTerm=").append(logLastTerm)
+                .append(", followerId=").append(followerId).append("]");
+        return builder.toString();
     }
 }
index 6337f8f6dce4f9cae5f223c4178f5095fb902c82..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())
@@ -102,4 +103,15 @@ public class InstallSnapshot extends AbstractRaftRPC {
 
         return installSnapshot;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("InstallSnapshot [term=").append(term).append(", leaderId=").append(leaderId)
+                .append(", lastIncludedIndex=").append(lastIncludedIndex).append(", lastIncludedTerm=")
+                .append(lastIncludedTerm).append(", data=").append(data).append(", chunkIndex=").append(chunkIndex)
+                .append(", totalChunks=").append(totalChunks).append(", lastChunkHashCode=").append(lastChunkHashCode)
+                .append("]");
+        return builder.toString();
+    }
 }
index 15621bf894b14f75ec845821654202877f4b4382..77efa53dfd9c627ff3b585e67471f21a47cce123 100644 (file)
@@ -36,4 +36,12 @@ public class InstallSnapshotReply extends AbstractRaftRPC {
     public boolean isSuccess() {
         return success;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("InstallSnapshotReply [term=").append(term).append(", followerId=").append(followerId)
+                .append(", chunkIndex=").append(chunkIndex).append(", success=").append(success).append("]");
+        return builder.toString();
+    }
 }
index 9ba5acb664700f4873d51fdb9f2637ef882c360e..8f162ae254ac1d9faaefbc89e8d6bed33dbd1b85 100644 (file)
@@ -64,14 +64,12 @@ public class RequestVote extends AbstractRaftRPC {
         this.lastLogTerm = lastLogTerm;
     }
 
-    @Override public String toString() {
-        final StringBuilder sb =
-            new StringBuilder("RequestVote{");
-        sb.append("term='").append(getTerm()).append('\'');
-        sb.append("candidateId='").append(candidateId).append('\'');
-        sb.append(", lastLogIndex=").append(lastLogIndex);
-        sb.append(", lastLogTerm=").append(lastLogTerm);
-        sb.append('}');
-        return sb.toString();
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("RequestVote [term=").append(term).append(", candidateId=").append(candidateId)
+                .append(", lastLogIndex=").append(lastLogIndex).append(", lastLogTerm=").append(lastLogTerm)
+                .append("]");
+        return builder.toString();
     }
 }
index b3c95d6ecaab2b19524fb4ae06c3c8f6491658c0..865d4c287bd7b63cd051ef46b8db2b959f69d4b1 100644 (file)
@@ -27,4 +27,11 @@ public class RequestVoteReply extends AbstractRaftRPC {
     public boolean isVoteGranted() {
         return voteGranted;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("RequestVoteReply [term=").append(term).append(", voteGranted=").append(voteGranted).append("]");
+        return builder.toString();
+    }
 }
index ffd8edfbe15fa3aad7a9f237a053b23017946337..885c3ab1094eb68d677fad1728fcbf6046e8f127 100644 (file)
@@ -20,6 +20,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockReplicatedLogEntry;
+
 /**
 *
 */
@@ -130,11 +131,17 @@ public class AbstractReplicatedLogImplTest {
 
     @Test
     public void testSnapshotPreCommit() {
+        //add 4 more entries
         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("E")));
         replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("F")));
         replicatedLogImpl.append(new MockReplicatedLogEntry(3, 6, new MockPayload("G")));
         replicatedLogImpl.append(new MockReplicatedLogEntry(3, 7, new MockPayload("H")));
 
+        //sending negative values should not cause any changes
+        replicatedLogImpl.snapshotPreCommit(-1, -1);
+        assertEquals(8, replicatedLogImpl.size());
+        assertEquals(-1, replicatedLogImpl.getSnapshotIndex());
+
         replicatedLogImpl.snapshotPreCommit(4, 3);
         assertEquals(3, replicatedLogImpl.size());
         assertEquals(4, replicatedLogImpl.getSnapshotIndex());
@@ -152,7 +159,31 @@ public class AbstractReplicatedLogImplTest {
         assertEquals(0, replicatedLogImpl.size());
         assertEquals(7, replicatedLogImpl.getSnapshotIndex());
 
+    }
+
+    @Test
+    public void testIsPresent() {
+        assertTrue(replicatedLogImpl.isPresent(0));
+        assertTrue(replicatedLogImpl.isPresent(1));
+        assertTrue(replicatedLogImpl.isPresent(2));
+        assertTrue(replicatedLogImpl.isPresent(3));
+
+        replicatedLogImpl.append(new MockReplicatedLogEntry(2, 4, new MockPayload("D")));
+        replicatedLogImpl.snapshotPreCommit(3, 2); //snapshot on 3
+        replicatedLogImpl.snapshotCommit();
+
+        assertFalse(replicatedLogImpl.isPresent(0));
+        assertFalse(replicatedLogImpl.isPresent(1));
+        assertFalse(replicatedLogImpl.isPresent(2));
+        assertFalse(replicatedLogImpl.isPresent(3));
+        assertTrue(replicatedLogImpl.isPresent(4));
+
+        replicatedLogImpl.snapshotPreCommit(4, 2); //snapshot on 4
+        replicatedLogImpl.snapshotCommit();
+        assertFalse(replicatedLogImpl.isPresent(4));
 
+        replicatedLogImpl.append(new MockReplicatedLogEntry(2, 5, new MockPayload("D")));
+        assertTrue(replicatedLogImpl.isPresent(5));
     }
 
     // create a snapshot for test
index 4d33152b41ca1a575d086a5ca04be8437e25d52b..24581d6d2ae35aa6c1aca6f2efede8132dbc73ba 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) {
@@ -255,6 +256,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 +318,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 56bf6200dc4d328aec1a35b6a35470609fa5cc7e..ba8f49d8f6249b5ae3b4340128eeea2a9dc1bc3e 100644 (file)
@@ -60,7 +60,7 @@ import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply;
-import org.opendaylight.controller.cluster.raft.base.messages.InitiateInstallSnapshot;
+import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat;
 import org.opendaylight.controller.cluster.raft.behaviors.Follower;
 import org.opendaylight.controller.cluster.raft.behaviors.Leader;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
@@ -691,7 +691,7 @@ public class RaftActorTest extends AbstractActorTest {
                         new MockRaftActorContext.MockPayload("C"),
                         new MockRaftActorContext.MockPayload("D")));
 
-                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1, -1, 1));
+                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1,-1, 1, -1, 1));
 
                 RaftActorContext raftActorContext = mockRaftActor.getRaftActorContext();
 
@@ -737,7 +737,8 @@ public class RaftActorTest extends AbstractActorTest {
                 RaftActorContext raftActorContext = mockRaftActor.getRaftActorContext();
                 mockRaftActor.setCurrentBehavior(new Follower(raftActorContext));
 
-                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1, 2, 1));
+                long replicatedToAllIndex = 1;
+                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1, 2, 1, replicatedToAllIndex, 1));
 
                 verify(mockRaftActor.delegate).createSnapshot();
 
@@ -749,13 +750,16 @@ public class RaftActorTest extends AbstractActorTest {
 
                 verify(dataPersistenceProvider).deleteMessages(100);
 
-                assertEquals(2, mockRaftActor.getReplicatedLog().size());
+                assertEquals(3, mockRaftActor.getReplicatedLog().size());
+                assertEquals(1, mockRaftActor.getCurrentBehavior().getReplicatedToAllIndex());
 
+                assertNotNull(mockRaftActor.getReplicatedLog().get(2));
                 assertNotNull(mockRaftActor.getReplicatedLog().get(3));
                 assertNotNull(mockRaftActor.getReplicatedLog().get(4));
 
                 // Index 2 will not be in the log because it was removed due to snapshotting
-                assertNull(mockRaftActor.getReplicatedLog().get(2));
+                assertNull(mockRaftActor.getReplicatedLog().get(1));
+                assertNull(mockRaftActor.getReplicatedLog().get(0));
 
             }
         };
@@ -870,7 +874,7 @@ public class RaftActorTest extends AbstractActorTest {
 
                 mockRaftActor.setCurrentBehavior(new Leader(raftActorContext));
 
-                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1, -1, 1));
+                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1, -1, 1, -1, 1));
 
                 mockRaftActor.onReceiveCommand(new CaptureSnapshotReply(snapshotBytes.toByteArray()));
 
@@ -897,24 +901,24 @@ public class RaftActorTest extends AbstractActorTest {
             // sleeping for a minimum of 2 seconds, if it spans more its fine.
             Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
 
-            List<Object> matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
+            List<RoleChanged> 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());
@@ -962,7 +966,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 assertEquals(8, leaderActor.getReplicatedLog().size());
 
-                leaderActor.onReceiveCommand(new CaptureSnapshot(6, 1, 4, 1));
+                leaderActor.onReceiveCommand(new CaptureSnapshot(6, 1, 4, 1, 4, 1));
+
                 leaderActor.getRaftActorContext().setSnapshotCaptureInitiated(true);
                 verify(leaderActor.delegate).createSnapshot();
 
@@ -1040,19 +1045,21 @@ public class RaftActorTest extends AbstractActorTest {
 
                 followerActor.waitForInitializeBehaviorComplete();
 
-                // create 8 entries in the log - 0 to 4 are applied and will get picked up as part of the capture snapshot
+
                 Follower follower = new Follower(followerActor.getRaftActorContext());
                 followerActor.setCurrentBehavior(follower);
                 assertEquals(RaftState.Follower, followerActor.getCurrentBehavior().state());
 
+                // create 6 entries in the log - 0 to 4 are applied and will get picked up as part of the capture snapshot
                 MockRaftActorContext.MockReplicatedLogBuilder logBuilder = new MockRaftActorContext.MockReplicatedLogBuilder();
                 followerActor.getRaftActorContext().setReplicatedLog(logBuilder.createEntries(0, 6, 1).build());
 
-                // log as indices 0-5
+                // log has indices 0-5
                 assertEquals(6, followerActor.getReplicatedLog().size());
 
                 //snapshot on 4
-                followerActor.onReceiveCommand(new CaptureSnapshot(5, 1, 4, 1));
+                followerActor.onReceiveCommand(new CaptureSnapshot(5, 1, 4, 1, 4, 1));
+
                 followerActor.getRaftActorContext().setSnapshotCaptureInitiated(true);
                 verify(followerActor.delegate).createSnapshot();
 
@@ -1090,7 +1097,7 @@ public class RaftActorTest extends AbstractActorTest {
                 followerActor.onReceiveCommand(new CaptureSnapshotReply(snapshotBytes.toByteArray()));
                 assertFalse(followerActor.getRaftActorContext().isSnapshotCaptureInitiated());
 
-                // capture snapshot reply should remove the snapshotted entries only
+                // capture snapshot reply should remove the snapshotted entries only till replicatedToAllIndex
                 assertEquals(3, followerActor.getReplicatedLog().size()); //indexes 5,6,7 left in the log
                 assertEquals(7, followerActor.getReplicatedLog().lastIndex());
 
@@ -1150,19 +1157,25 @@ public class RaftActorTest extends AbstractActorTest {
                 // create 5 entries in the log
                 MockRaftActorContext.MockReplicatedLogBuilder logBuilder = new MockRaftActorContext.MockReplicatedLogBuilder();
                 leaderActor.getRaftActorContext().setReplicatedLog(logBuilder.createEntries(5, 10, 1).build());
+
                 //set the snapshot index to 4 , 0 to 4 are snapshotted
                 leaderActor.getRaftActorContext().getReplicatedLog().setSnapshotIndex(4);
+                //setting replicatedToAllIndex = 9, for the log to clear
+                leader.setReplicatedToAllIndex(9);
                 assertEquals(5, leaderActor.getReplicatedLog().size());
+                assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
 
                 leaderActor.onReceiveCommand(new AppendEntriesReply(follower1Id, 1, true, 9, 1));
                 assertEquals(5, leaderActor.getReplicatedLog().size());
+                assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
 
                 // set the 2nd follower nextIndex to 1 which has been snapshotted
                 leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 0, 1));
                 assertEquals(5, leaderActor.getReplicatedLog().size());
+                assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
 
                 // simulate a real snapshot
-                leaderActor.onReceiveCommand(new InitiateInstallSnapshot());
+                leaderActor.onReceiveCommand(new SendHeartBeat());
                 assertEquals(5, leaderActor.getReplicatedLog().size());
                 assertEquals(String.format("expected to be Leader but was %s. Current Leader = %s ",
                         leaderActor.getCurrentBehavior().state(), leaderActor.getLeaderId())
@@ -1182,7 +1195,7 @@ public class RaftActorTest extends AbstractActorTest {
                 leaderActor.onReceiveCommand(new CaptureSnapshotReply(snapshotBytes.toByteArray()));
                 assertFalse(leaderActor.getRaftActorContext().isSnapshotCaptureInitiated());
 
-                assertEquals("Real snapshot didn't clear the log till lastApplied", 0, leaderActor.getReplicatedLog().size());
+                assertEquals("Real snapshot didn't clear the log till replicatedToAllIndex", 0, leaderActor.getReplicatedLog().size());
 
                 //reply from a slow follower after should not raise errors
                 leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 5, 1));
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
index 42a7911be31f3411c3467435bec446dfef15ecb7..f56755b447d347981b687cf017eded1caa059ea6 100644 (file)
@@ -1,32 +1,52 @@
 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 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;
 
-import java.util.ArrayList;
-import java.util.List;
+public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+    protected final TestActorFactory actorFactory = new TestActorFactory(getSystem());
 
-public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
+    private final TestActorRef<MessageCollectorActor> behaviorActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("behavior"));
+
+    RaftActorBehavior behavior;
 
-    private final ActorRef behaviorActor = getSystem().actorOf(Props.create(
-        DoNothingActor.class));
+    @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
@@ -36,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());
-
-
-        }};
     }
 
 
@@ -63,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());
     }
 
     /**
@@ -209,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());
     }
 
 
@@ -265,87 +206,81 @@ 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
-    public void testFakeSnapshots() {
+    public void testPerformSnapshot() {
         MockRaftActorContext context = new MockRaftActorContext("test", getSystem(), behaviorActor);
-        AbstractRaftActorBehavior behavior = new Leader(context);
-        context.getTermInformation().update(1, "leader");
+        AbstractRaftActorBehavior abstractBehavior =  (AbstractRaftActorBehavior) createBehavior(context);
+        if (abstractBehavior instanceof Candidate) {
+            return;
+        }
+
+        context.getTermInformation().update(1, "test");
 
-        //entry with 1 index=0 entry with replicatedToAllIndex = 0, does not do anything, returns the
+        //log has 1 entry with replicatedToAllIndex = 0, does not do anything, returns the
         context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 1, 1).build());
         context.setLastApplied(0);
-        assertEquals(-1, behavior.fakeSnapshot(0, -1));
+        abstractBehavior.performSnapshotWithoutCapture(0);
+        assertEquals(-1, abstractBehavior.getReplicatedToAllIndex());
         assertEquals(1, context.getReplicatedLog().size());
 
         //2 entries, lastApplied still 0, no purging.
-        context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0,2,1).build());
+        context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 2, 1).build());
         context.setLastApplied(0);
-        assertEquals(-1, behavior.fakeSnapshot(0, -1));
+        abstractBehavior.performSnapshotWithoutCapture(0);
+        assertEquals(-1, abstractBehavior.getReplicatedToAllIndex());
         assertEquals(2, context.getReplicatedLog().size());
 
         //2 entries, lastApplied still 0, no purging.
-        context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0,2,1).build());
+        context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 2, 1).build());
         context.setLastApplied(1);
-        assertEquals(0, behavior.fakeSnapshot(0, -1));
+        abstractBehavior.performSnapshotWithoutCapture(0);
+        assertEquals(0, abstractBehavior.getReplicatedToAllIndex());
         assertEquals(1, context.getReplicatedLog().size());
 
         //5 entries, lastApplied =2 and replicatedIndex = 3, but since we want to keep the lastapplied, indices 0 and 1 will only get purged
-        context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0,5,1).build());
+        context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 5, 1).build());
         context.setLastApplied(2);
-        assertEquals(1, behavior.fakeSnapshot(3, 1));
+        abstractBehavior.performSnapshotWithoutCapture(3);
+        assertEquals(1, abstractBehavior.getReplicatedToAllIndex());
         assertEquals(3, context.getReplicatedLog().size());
 
-
+        // scenario where Last applied > Replicated to all index (becoz of a slow follower)
+        context.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        context.setLastApplied(2);
+        abstractBehavior.performSnapshotWithoutCapture(1);
+        assertEquals(1, abstractBehavior.getReplicatedToAllIndex());
+        assertEquals(1, context.getReplicatedLog().size());
     }
 
-    protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(
-        ActorRef actorRef, RaftRPC rpc) {
 
-        RaftActorContext actorContext = createActorContext();
+    protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(RaftActorContext actorContext,
+            ActorRef actorRef, RaftRPC rpc) throws Exception {
+
         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(
@@ -354,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);
 
@@ -371,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);
     }
 
@@ -398,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..b37ace9560b4bfa46984cb030f310541717a2d63 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 AbstractRaftActorBehaviorTest {
 
-    private ActorRef leaderActor =
-        getSystem().actorOf(Props.create(DoNothingActor.class));
+    private final TestActorRef<MessageCollectorActor> leaderActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("leader"));
+
+    private final TestActorRef<MessageCollectorActor> senderActor = actorFactory.createTestActor(
+            Props.create(MessageCollectorActor.class), actorFactory.generateActorId("sender"));
+
+    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) {
+    protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
         return new Leader(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 8251c6b265bd5ca85e247119104b4e6b268be9f6..34e1ed9b3b3478032c86e9058998ac23610c7c97 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;
@@ -31,817 +30,656 @@ import org.opendaylight.controller.cluster.raft.SerializationUtils;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
-import org.opendaylight.controller.cluster.raft.base.messages.InitiateInstallSnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.IsolatedLeaderCheck;
 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.MessageCollectorActor;
 import org.opendaylight.controller.protobuff.messages.cluster.raft.InstallSnapshotMessages;
 import scala.concurrent.duration.FiniteDuration;
 
 public class LeaderTest extends AbstractRaftActorBehaviorTest {
 
-    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();
+
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            //update follower timestamp
-            leader.markFollowerActive(followerActor.path().toString());
+        //clears leaders log
+        actorContext.getReplicatedLog().removeFrom(0);
 
-            ByteString bs = toByteString(leadersSnapshot);
-            leader.setSnapshot(Optional.of(bs));
-            leader.createFollowerToSnapshot(followerActor.path().toString(), bs);
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int newEntryIndex = 4;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            //send first chunk and no InstallSnapshotReply received yet
-            leader.getFollowerToSnapshot().getNextChunk();
-            leader.getFollowerToSnapshot().incrementChunkIndex();
+        // 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));
 
-            Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(),
-                TimeUnit.MILLISECONDS);
+        leader = new Leader(actorContext);
+
+        // new entry
+        ReplicatedLogImplEntry entry =
+                new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
+                        new MockRaftActorContext.MockPayload("D"));
 
-            leader.handleMessage(leaderActor, new SendHeartBeat());
+        //update follower timestamp
+        leader.markFollowerActive(FOLLOWER_ID);
 
-            AppendEntries aeproto = MessageCollectorActor.getFirstMatching(
-                followerActor, AppendEntries.class);
+        ByteString bs = toByteString(leadersSnapshot);
+        leader.setSnapshot(Optional.of(bs));
+        FollowerToSnapshot fts = leader.new FollowerToSnapshot(bs);
+        leader.setFollowerSnapshot(FOLLOWER_ID, fts);
 
-            assertNotNull("AppendEntries should be sent even if InstallSnapshotReply is not " +
-                "received", aeproto);
+        //send first chunk and no InstallSnapshotReply received yet
+        fts.getNextChunk();
+        fts.incrementChunkIndex();
 
-            AppendEntries ae = (AppendEntries) SerializationUtils.fromSerializable(aeproto);
+        Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(),
+                TimeUnit.MILLISECONDS);
 
-            assertTrue("AppendEntries should be sent with empty entries", ae.getEntries().isEmpty());
+        leader.handleMessage(leaderActor, new SendHeartBeat());
 
-            //InstallSnapshotReply received
-            leader.getFollowerToSnapshot().markSendStatus(true);
+        AppendEntries aeproto = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            leader.handleMessage(senderActor, new SendHeartBeat());
+        AppendEntries ae = (AppendEntries) SerializationUtils.fromSerializable(aeproto);
 
-            InstallSnapshotMessages.InstallSnapshot isproto = MessageCollectorActor.getFirstMatching(followerActor,
-                InstallSnapshot.SERIALIZABLE_CLASS);
+        assertTrue("AppendEntries should be sent with empty entries", ae.getEntries().isEmpty());
 
-            assertNotNull("Installsnapshot should get called for sending the next chunk of snapshot",
-                isproto);
+        //InstallSnapshotReply received
+        fts.markSendStatus(true);
 
-            InstallSnapshot is = (InstallSnapshot) SerializationUtils.fromSerializable(isproto);
+        leader.handleMessage(leaderActor, new SendHeartBeat());
 
-            assertEquals(snapshotIndex, is.getLastIncludedIndex());
+        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 InitiateInstallSnapshot
-            Boolean[] matches = new ReceiveWhile<Boolean>(Boolean.class, duration("2 seconds")) {
-                @Override
-                protected Boolean match(Object o) throws Exception {
-                    if (o instanceof InitiateInstallSnapshot) {
-                        return true;
-                    }
-                    return false;
-                }
-            }.get();
-
-            boolean initiateInitiateInstallSnapshot = false;
-            for (Boolean b: matches) {
-                initiateInitiateInstallSnapshot = b | initiateInitiateInstallSnapshot;
-            }
+        assertTrue(raftBehavior instanceof Leader);
 
-            assertTrue(initiateInitiateInstallSnapshot);
-        }};
+        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();
 
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            MockRaftActorContext actorContext =
-                (MockRaftActorContext) createActorContext(leaderActor);
-            actorContext.setPeerAddresses(peerAddresses);
+        //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");
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int newEntryIndex = 4;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            //clears leaders log
-            actorContext.getReplicatedLog().removeFrom(0);
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.setLastApplied(3);
+        actorContext.setCommitIndex(followersLastIndex);
 
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int newEntryIndex = 4;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
+        leader = new Leader(actorContext);
 
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.setLastApplied(3);
-            actorContext.setCommitIndex(followersLastIndex);
+        // Leader will send an immediate heartbeat - ignore it.
+        MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
 
-            Leader leader = new Leader(actorContext);
-            // set the snapshot as absent and check if capture-snapshot is invoked.
-            leader.setSnapshot(Optional.<ByteString>absent());
+        // set the snapshot as absent and check if capture-snapshot is invoked.
+        leader.setSnapshot(Optional.<ByteString>absent());
 
-            // new entry
-            ReplicatedLogImplEntry entry =
-                new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
-                    new MockRaftActorContext.MockPayload("D"));
+        // new entry
+        ReplicatedLogImplEntry entry = new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
+                new MockRaftActorContext.MockPayload("D"));
 
-            actorContext.getReplicatedLog().append(entry);
+        actorContext.getReplicatedLog().append(entry);
 
-            // this should invoke a sendinstallsnapshot as followersLastIndex < snapshotIndex
-            RaftActorBehavior raftBehavior = leader.handleMessage(
-                leaderActor, new InitiateInstallSnapshot());
+        //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
-            raftBehavior = leader.handleMessage(leaderActor, new InitiateInstallSnapshot());
-            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());
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
 
-            final int followersLastIndex = 2;
-            final int snapshotIndex = 3;
-            final int snapshotTerm = 1;
-            final int currentTerm = 2;
+        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();
+        }
 
-            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));
+        //clears leaders log
+        actorContext.getReplicatedLog().removeFrom(0);
 
-            actorContext.setConfigParams(configParams);
-            actorContext.setPeerAddresses(peerAddresses);
-            actorContext.setCommitIndex(followersLastIndex);
+        RaftActorBehavior raftBehavior = leader.handleMessage(followerActor,
+                new InstallSnapshotReply(currentTerm, FOLLOWER_ID, fts.getChunkIndex(), true));
 
-            MockLeader leader = new MockLeader(actorContext);
+        assertTrue(raftBehavior instanceof Leader);
 
-            Map<String, String> leadersSnapshot = new HashMap<>();
-            leadersSnapshot.put("1", "A");
-            leadersSnapshot.put("2", "B");
-            leadersSnapshot.put("3", "C");
+        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());
+    }
 
-            // set the snapshot variables in replicatedlog
-            actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
-            actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
-            actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
+    @Test
+    public void testSendSnapshotfromInstallSnapshotReply() throws Exception {
+        logStart("testSendSnapshotfromInstallSnapshotReply");
 
-            ByteString bs = toByteString(leadersSnapshot);
-            leader.setSnapshot(Optional.of(bs));
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-            leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-            List<Object> objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        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.setConfigParams(configParams);
+        actorContext.setCommitIndex(followersLastIndex);
 
-            assertEquals(1, objectList.size());
+        leader = new Leader(actorContext);
 
-            Object o = objectList.get(0);
-            assertTrue(o instanceof InstallSnapshotMessages.InstallSnapshot);
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
 
-            InstallSnapshotMessages.InstallSnapshot installSnapshot = (InstallSnapshotMessages.InstallSnapshot) o;
+        // set the snapshot variables in replicatedlog
+        actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+        actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+        actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
 
-            assertEquals(1, installSnapshot.getChunkIndex());
-            assertEquals(3, installSnapshot.getTotalChunks());
+        ByteString bs = toByteString(leadersSnapshot);
+        leader.setSnapshot(Optional.of(bs));
 
-            leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
-                "follower-reply", installSnapshot.getChunkIndex(), true));
+        leader.handleMessage(leaderActor, new SendInstallSnapshot(bs));
 
-            objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        InstallSnapshotMessages.InstallSnapshot installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-            assertEquals(2, objectList.size());
+        assertEquals(1, installSnapshot.getChunkIndex());
+        assertEquals(3, installSnapshot.getTotalChunks());
 
-            installSnapshot = (InstallSnapshotMessages.InstallSnapshot) objectList.get(1);
+        followerActor.underlyingActor().clear();
+        leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
+                FOLLOWER_ID, installSnapshot.getChunkIndex(), true));
 
-            leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(),
-                "follower-reply", installSnapshot.getChunkIndex(), true));
+        installSnapshot = MessageCollectorActor.expectFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-            objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        assertEquals(2, 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));
+        // 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));
 
-            objectList = MessageCollectorActor.getAllMatching(followerActor,
-                InstallSnapshotMessages.InstallSnapshot.class);
+        installSnapshot = MessageCollectorActor.getFirstMatching(
+                followerActor, InstallSnapshotMessages.InstallSnapshot.class);
 
-            // Count should still stay at 3
-            assertEquals(3, objectList.size());
-        }};
+        Assert.assertNull(installSnapshot);
     }
 
 
     @Test
     public void testHandleInstallSnapshotReplyWithInvalidChunkIndex() throws Exception{
-        new JavaTestKit(getSystem()) {{
+        logStart("testHandleInstallSnapshotReplyWithInvalidChunkIndex");
 
-            TestActorRef<MessageCollectorActor> followerActor =
-                    TestActorRef.create(getSystem(), Props.create(MessageCollectorActor.class), "follower");
+        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 snapshotTerm = 1;
-            final int currentTerm = 2;
-
-            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");
+        logStart("testHandleSnapshotSendsPreviousChunksHashCodeWhenSendingNextChunk");
 
-                Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put(followerActor.path().toString(),
-                        followerActor.path().toString());
+        MockRaftActorContext actorContext = createActorContextWithFollower();
 
-                final int followersLastIndex = 2;
-                final int snapshotIndex = 3;
-                final int snapshotTerm = 1;
-                final int currentTerm = 2;
+        final int followersLastIndex = 2;
+        final int snapshotIndex = 3;
+        final int snapshotTerm = 1;
+        final int currentTerm = 2;
 
-                MockRaftActorContext actorContext =
-                        (MockRaftActorContext) createActorContext();
-
-                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
@@ -850,7 +688,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");
@@ -860,7 +698,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;
@@ -872,64 +712,50 @@ 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;
 
@@ -948,310 +774,248 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
 
     @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().behavior = 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().behavior = 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().behavior = leader;
+        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()) {
-            {
+        logStart("testHandleAppendEntriesReplyFailure");
 
-                ActorRef leaderActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        MockRaftActorContext leaderActorContext = createActorContextWithFollower();
 
-                ActorRef followerActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        leader = new Leader(leaderActorContext);
 
+        // Send initial heartbeat reply with last index.
+        leader.handleAppendEntriesReply(followerActor, new AppendEntriesReply(FOLLOWER_ID, 1, true, 10, 1));
 
-                MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        FollowerLogInformation followerInfo = leader.getFollower(FOLLOWER_ID);
+        assertEquals("getNextIndex", 11, followerInfo.getNextIndex());
 
-                Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put("follower-1",
-                    followerActor.path().toString());
+        AppendEntriesReply reply = new AppendEntriesReply(FOLLOWER_ID, 1, false, 10, 1);
 
-                leaderActorContext.setPeerAddresses(peerAddresses);
+        RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
 
-                Leader leader = new Leader(leaderActorContext);
+        assertEquals(RaftState.Leader, raftActorBehavior.state());
 
-                AppendEntriesReply reply = new AppendEntriesReply("follower-1", 1, false, 10, 1);
-
-                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));
-
-                ActorRef followerActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
-
+        logStart("testHandleAppendEntriesReplySuccess");
 
-                MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        MockRaftActorContext leaderActorContext = createActorContextWithFollower();
 
-                leaderActorContext.setReplicatedLog(
-                    new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        leaderActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
 
-                Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put("follower-1",
-                    followerActor.path().toString());
+        leaderActorContext.setCommitIndex(1);
+        leaderActorContext.setLastApplied(1);
+        leaderActorContext.getTermInformation().update(1, "leader");
 
-                leaderActorContext.setPeerAddresses(peerAddresses);
-                leaderActorContext.setCommitIndex(1);
-                leaderActorContext.setLastApplied(1);
-                leaderActorContext.getTermInformation().update(1, "leader");
+        leader = new Leader(leaderActorContext);
 
-                Leader leader = new Leader(leaderActorContext);
+        AppendEntriesReply reply = new AppendEntriesReply(FOLLOWER_ID, 1, true, 2, 1);
 
-                AppendEntriesReply reply = new AppendEntriesReply("follower-1", 1, true, 2, 1);
+        RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
 
-                RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
+        assertEquals(RaftState.Leader, raftActorBehavior.state());
 
-                assertEquals(RaftState.Leader, raftActorBehavior.state());
+        assertEquals(2, leaderActorContext.getCommitIndex());
 
-                assertEquals(2, leaderActorContext.getCommitIndex());
+        ApplyLogEntries applyLogEntries = MessageCollectorActor.expectFirstMatching(
+                leaderActor, ApplyLogEntries.class);
 
-                ApplyLogEntries applyLogEntries =
-                    MessageCollectorActor.getFirstMatching(leaderActor,
-                    ApplyLogEntries.class);
+        assertEquals(2, leaderActorContext.getLastApplied());
 
-                assertNotNull(applyLogEntries);
+        assertEquals(2, applyLogEntries.getToIndex());
 
-                assertEquals(2, leaderActorContext.getLastApplied());
+        List<ApplyState> applyStateList = MessageCollectorActor.getAllMatching(leaderActor,
+                ApplyState.class);
 
-                assertEquals(2, applyLogEntries.getToIndex());
+        assertEquals(1,applyStateList.size());
 
-                List<Object> applyStateList = MessageCollectorActor.getAllMatching(leaderActor,
-                    ApplyState.class);
+        ApplyState applyState = applyStateList.get(0);
 
-                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()) {
-            {
+        logStart("testHandleAppendEntriesReplyUnknownFollower");
 
-                ActorRef leaderActor =
-                    getSystem().actorOf(Props.create(MessageCollectorActor.class));
+        MockRaftActorContext leaderActorContext = createActorContext();
 
-                MockRaftActorContext leaderActorContext =
-                    new MockRaftActorContext("leader", getSystem(), leaderActor);
+        leader = new Leader(leaderActorContext);
 
-                Leader leader = new Leader(leaderActorContext);
+        AppendEntriesReply reply = new AppendEntriesReply("unkown-follower", 1, false, 10, 1);
 
-                AppendEntriesReply reply = new AppendEntriesReply("follower-1", 1, false, 10, 1);
+        RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
 
-                RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(getRef(), 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();
-
-            MockRaftActorContext leaderActorContext =
-                new MockRaftActorContext("leader", getSystem(), leaderActor);
+        logStart("testIsolatedLeaderCheckNoFollowers");
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            leaderActorContext.setPeerAddresses(peerAddresses);
+        MockRaftActorContext leaderActorContext = createActorContext();
 
-            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());
@@ -1259,8 +1023,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");
@@ -1292,118 +1055,90 @@ 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);
+        MockRaftActorContext leaderActorContext = createActorContextWithFollower();
 
-            DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
-            //configParams.setHeartBeatInterval(new FiniteDuration(9, TimeUnit.SECONDS));
-            configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
+        DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
+        //configParams.setHeartBeatInterval(new FiniteDuration(9, TimeUnit.SECONDS));
+        configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(10, TimeUnit.SECONDS));
 
-            leaderActorContext.setConfigParams(configParams);
+        leaderActorContext.setConfigParams(configParams);
 
-            TestActorRef<ForwardMessageToBehaviorActor> followerActor = TestActorRef.create(getSystem(),
-                    ForwardMessageToBehaviorActor.props());
+        MockRaftActorContext followerActorContext = createActorContext(FOLLOWER_ID, followerActor);
 
-            MockRaftActorContext followerActorContext =
-                    new MockRaftActorContext("follower-reply", getSystem(), followerActor);
+        followerActorContext.setConfigParams(configParams);
 
-            followerActorContext.setConfigParams(configParams);
+        Follower follower = new Follower(followerActorContext);
+        followerActor.underlyingActor().behavior = follower;
 
-            Follower follower = new Follower(followerActorContext);
-            followerActor.underlyingActor().behavior = follower;
+        leaderActorContext.getReplicatedLog().removeFrom(0);
+        leaderActorContext.setCommitIndex(-1);
+        leaderActorContext.setLastApplied(-1);
 
-            Map<String, String> peerAddresses = new HashMap<>();
-            peerAddresses.put("follower-reply",
-                    followerActor.path().toString());
+        followerActorContext.getReplicatedLog().removeFrom(0);
+        followerActorContext.setCommitIndex(-1);
+        followerActorContext.setLastApplied(-1);
 
-            leaderActorContext.setPeerAddresses(peerAddresses);
+        leader = new Leader(leaderActorContext);
 
-            leaderActorContext.getReplicatedLog().removeFrom(0);
-            leaderActorContext.setCommitIndex(-1);
-            leaderActorContext.setLastApplied(-1);
+        AppendEntriesReply appendEntriesReply = MessageCollectorActor.expectFirstMatching(
+                leaderActor, AppendEntriesReply.class);
 
-            followerActorContext.getReplicatedLog().removeFrom(0);
-            followerActorContext.setCommitIndex(-1);
-            followerActorContext.setLastApplied(-1);
+        leader.handleMessage(followerActor, appendEntriesReply);
 
-            Leader leader = new Leader(leaderActorContext);
+        // Clear initial heartbeat messages
 
-            AppendEntriesReply appendEntriesReply = MessageCollectorActor.getFirstMatching(
-                    leaderActor, AppendEntriesReply.class);
-            assertNotNull(appendEntriesReply);
-            System.out.println("appendEntriesReply: "+appendEntriesReply);
-            leader.handleMessage(followerActor, appendEntriesReply);
+        leaderActor.underlyingActor().clear();
+        followerActor.underlyingActor().clear();
 
-            // Clear initial heartbeat messages
+        // create 3 entries
+        leaderActorContext.setReplicatedLog(
+                new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
+        leaderActorContext.setCommitIndex(1);
+        leaderActorContext.setLastApplied(1);
 
-            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);
+        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 {
-
-        FollowerToSnapshot fts;
-
-        public MockLeader(RaftActorContext context){
-            super(context);
-        }
-
-        public FollowerToSnapshot getFollowerToSnapshot() {
-            return fts;
-        }
-
-        public void createFollowerToSnapshot(String followerId, ByteString bs ) {
-            fts = new FollowerToSnapshot(bs);
-            setFollowerSnapshot(followerId, fts);
-        }
+    @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 {
index 79c90cf051cc928ac50e563a136c62030809bbc2..662c12180d29acc65851f6a28e64590ffe2b5463 100644 (file)
@@ -18,6 +18,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 +64,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;
+    }
+
+    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(100, TimeUnit.MILLISECONDS);
+            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);
             }
         }
 
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
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 95ee21674a579ef262231eef71158a6371c4fc14..432c2d5615227d7d67f856bef6215fd550053084 100644 (file)
@@ -20,8 +20,8 @@ public abstract class AbstractUntypedPersistentActor extends UntypedPersistentAc
     protected final Logger LOG = LoggerFactory.getLogger(getClass());
 
     public AbstractUntypedPersistentActor() {
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Actor created {}", getSelf());
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("Actor created {}", getSelf());
         }
         getContext().
             system().
@@ -33,24 +33,24 @@ public abstract class AbstractUntypedPersistentActor extends UntypedPersistentAc
 
     @Override public void onReceiveCommand(Object message) throws Exception {
         final String messageType = message.getClass().getSimpleName();
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Received message {}", messageType);
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("Received message {}", messageType);
         }
         handleCommand(message);
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Done handling message {}", messageType);
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("Done handling message {}", messageType);
         }
 
     }
 
     @Override public void onReceiveRecover(Object message) throws Exception {
         final String messageType = message.getClass().getSimpleName();
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Received message {}", messageType);
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("Received message {}", messageType);
         }
         handleRecover(message);
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Done handling message {}", messageType);
+        if(LOG.isTraceEnabled()) {
+            LOG.trace("Done handling message {}", messageType);
         }
 
     }
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 87a0fb931edb171ca8e2bb7d4563ff1172de4912..21d74a6e1a37d49ad9ea6e53b731014e4020f01b 100644 (file)
@@ -229,10 +229,6 @@ public class Shard extends RaftActor {
 
     @Override
     public void onReceiveCommand(final Object message) throws Exception {
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("{}: onReceiveCommand: Received message {} from {}", persistenceId(), message, getSender());
-        }
-
         if (message.getClass().equals(CreateTransaction.SERIALIZABLE_CLASS)) {
             handleCreateTransaction(message);
         } else if(message instanceof ForwardedReadyTransaction) {
index 1e2386ae1bb8ea4ae6075266bbf12f56600c0516..af25df13d2865ba867d6a529d3ad947101b1510a 100644 (file)
@@ -134,7 +134,7 @@ public abstract class ShardTransaction extends AbstractUntypedActorWithMetering
             sender().tell((returnSerialized ? readDataReply.toSerializable(clientTxVersion): readDataReply), self());
 
         } catch (Exception e) {
-            LOG.error(String.format("Unexpected error reading path %s", path), e);
+            LOG.debug(String.format("Unexpected error reading path %s", path), e);
             shardStats.incrementFailedReadTransactionsCount();
             sender().tell(new akka.actor.Status.Failure(e), self());
         }
index 4f472266c1f56acbd8fc531ae7189f1ae91951b4..c51ea80726e54d9cf656e193ca8521d242206c76 100644 (file)
@@ -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 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 94b9698abf3a06f41527a83e5cec2461b2658266..4b0651a48eb07f4814bd990386bbe94d32159dfd 100644 (file)
@@ -1467,7 +1467,7 @@ public class ShardTest extends AbstractActorTest {
 
             NormalizedNode<?,?> expectedRoot = readStore(shard, YangInstanceIdentifier.builder().build());
 
-            CaptureSnapshot capture = new CaptureSnapshot(-1, -1, -1, -1);
+            CaptureSnapshot capture = new CaptureSnapshot(-1, -1, -1, -1, -1, -1);
             shard.tell(capture, getRef());
 
             assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS));
index d2396e0524f340844ea5f7c0e35dfd6cad0b4806..b013515f2595950cba669ac08dfdb1a8eefe37fa 100644 (file)
@@ -71,7 +71,7 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
         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 1976913a1744e9ff8ba782a85dd83fdd79e2682c..4e6c7a5f7f2964dc8b4655c7a3d73d508409ae5a 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.md.sal.dom.api;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import java.util.Objects;
 import javax.annotation.Nonnull;
@@ -119,6 +120,6 @@ public abstract class DOMRpcIdentifier {
 
     @Override
     public final String toString() {
-        return com.google.common.base.Objects.toStringHelper(this).omitNullValues().add("type", type).add("contextReference", getContextReference()).toString();
+        return MoreObjects.toStringHelper(this).omitNullValues().add("type", type).add("contextReference", getContextReference()).toString();
     }
 }
index da592e9b22689704b393f6b2f7d4b9588ddb9bed..5d086e59a74e98803a58344285fba89339117d19 100644 (file)
@@ -8,11 +8,14 @@
 package org.opendaylight.controller.sal.core.api;
 
 import java.util.concurrent.Future;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
+/**
+ * @deprecated Use {@link org.opendaylight.controller.md.sal.dom.api.DOMRpcService} instead.
+ */
+@Deprecated
 public interface RpcConsumptionRegistry {
     /**
      * Sends an RPC to other components registered to the broker.
index d14910055b6a8ff2f72805599588060dc7f663c6..5055ad1430b1d584f9918e8b76101d766105a543 100644 (file)
@@ -7,14 +7,12 @@
  */
 package org.opendaylight.controller.sal.core.api;
 
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Set;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
-import com.google.common.util.concurrent.ListenableFuture;
-
 /**
  * {@link Provider}'s implementation of an RPC.
  *
@@ -42,7 +40,10 @@ import com.google.common.util.concurrent.ListenableFuture;
  * {@link RpcResult}
  * <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}
  * </ol>
+ *
+ * @deprecated Use {@link org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation} instead.
  */
+@Deprecated
 public interface RpcImplementation extends Provider.ProviderFunctionality {
 
     /**
index 371082223abad5109c40fa74f7755ee469a9e895..45f13654d840442831c0ba799c08fea5d2bbca92 100644 (file)
@@ -9,7 +9,10 @@ package org.opendaylight.controller.sal.core.api;
 
 /**
  * Exception reported when no RPC implementation is found in the system.
+ *
+ * @deprecated Use {@link org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException} instead.
  */
+@Deprecated
 public class RpcImplementationUnavailableException extends RuntimeException {
     private static final long serialVersionUID = 1L;
 
index 050225c5c20f42e4fea8eabf26577051a09aa8a7..1caed094374480fcf00beab5f128979cb1e27dfb 100644 (file)
@@ -15,6 +15,10 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
+/**
+ * @deprecated Use {@link org.opendaylight.controller.md.sal.dom.api.DOMRpcProviderService} and {@link org.opendaylight.controller.md.sal.dom.api.DOMRpcService} instead.
+ */
+@Deprecated
 public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, RouteChangePublisher<RpcRoutingContext, YangInstanceIdentifier>, DOMService {
 
     /**
index a0be886b24d7c10e892c598c4e8072fea7835a81..df20650ac470d693c24010cf760ba1c963b71b2c 100644 (file)
@@ -8,9 +8,12 @@
 package org.opendaylight.controller.sal.core.api;
 
 import java.util.EventListener;
-
 import org.opendaylight.yangtools.yang.common.QName;
 
+/**
+ * @deprecated Use {@link org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener} instead.
+ */
+@Deprecated
 public interface RpcRegistrationListener extends EventListener {
 
     public void onRpcImplementationAdded(QName name);
index fdb80ebcbef49bbaf17aa2981f3c322a6a2d47ab..51b28e14502459ae44cebeb6887828ac78c79648 100644 (file)
@@ -7,8 +7,8 @@
  */
 package org.opendaylight.controller.md.sal.dom.broker.impl;
 
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
@@ -73,7 +73,7 @@ final class PingPongTransaction implements FutureCallback<Void> {
 
     @Override
     public String toString() {
-        return addToStringAttributes(Objects.toStringHelper(this)).toString();
+        return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
     }
 
     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
index 34b41ccfcacd4f27d501ad7855980222aff350ad..0b72a32f1033884ba983c71b2651a4a88ad6c7b1 100644 (file)
@@ -11,6 +11,9 @@ 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;
 import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot;
@@ -24,6 +27,9 @@ public class DummyShard extends UntypedActor{
     private final Configuration configuration;
     private final String followerId;
     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;
@@ -54,12 +60,36 @@ public class DummyShard extends UntypedActor{
     }
 
     protected void handleAppendEntries(AppendEntries req) throws InterruptedException {
-        LOG.info("{} - Received AppendEntries message : leader term, index, size = {}, {}, {}", followerId, req.getTerm(),req.getLeaderCommit(), req.getEntries().size());
+        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());
+        }
+
+        lastMessageIndex = req.getLeaderCommit();
+        lastMessageSize = req.getEntries().size();
+
         long lastIndex = req.getLeaderCommit();
-        if (req.getEntries().size() > 0)
-            lastIndex = req.getEntries().get(0).getIndex();
+        if (req.getEntries().size() > 0) {
+            for(ReplicatedLogEntry entry : req.getEntries()) {
+                lastIndex = entry.getIndex();
+            }
+        }
 
-        if (configuration.shouldCauseTrouble()) {
+        if (configuration.shouldCauseTrouble() && req.getEntries().size() > 0) {
             boolean ignore = false;
 
             if (configuration.shouldDropReplies()) {
diff --git a/opendaylight/md-sal/sal-dummy-distributed-datastore/src/main/resources/simplelogger.properties b/opendaylight/md-sal/sal-dummy-distributed-datastore/src/main/resources/simplelogger.properties
new file mode 100644 (file)
index 0000000..cd2d082
--- /dev/null
@@ -0,0 +1,6 @@
+org.slf4j.simpleLogger.showDateTime=true
+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=error
\ No newline at end of file
index 6cc593904723ee6cf7a28f26fd0367703ec89371..8d040f612e82b70f59bff3feb45628cbb0ed9625 100644 (file)
@@ -7,10 +7,9 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Preconditions;
-
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
 import org.slf4j.Logger;
 
@@ -42,7 +41,7 @@ abstract class AbstractDOMStoreTransaction implements DOMStoreTransaction {
 
     @Override
     public final String toString() {
-        return addToStringAttributes(Objects.toStringHelper(this)).toString();
+        return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
     }
 
     /**
index 60a23403b3ac7fce67b01b85295752cdbb2a2e6e..faddbae850ce50753dc7ca1e7298bdc6e77c0f21 100644 (file)
@@ -8,7 +8,7 @@
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
 import static com.google.common.base.Preconditions.checkState;
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
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 1579d1927fef673b116f2827940970e9cf9ab103..f39a21d16b558e917cb7a86b145e5193c89345ff 100644 (file)
@@ -12,6 +12,7 @@ import static com.google.common.base.Preconditions.checkState;
 
 import java.util.Dictionary;
 import java.util.Hashtable;
+import org.opendaylight.controller.netconf.api.util.NetconfConstants;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
 import org.osgi.framework.BundleActivator;
@@ -91,7 +92,7 @@ public class Activator implements BundleActivator {
             NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
             LOG.debug("Registering into OSGi");
             Dictionary<String, String> properties = new Hashtable<>();
-            properties.put("name", "config-netconf-connector");
+            properties.put(NetconfConstants.SERVICE_NAME, NetconfConstants.CONFIG_NETCONF_CONNECTOR);
             osgiRegistration = context.registerService(NetconfOperationServiceFactory.class, factory, properties);
         }
     }
diff --git a/opendaylight/netconf/mdsal-netconf-connector/pom.xml b/opendaylight/netconf/mdsal-netconf-connector/pom.xml
new file mode 100644 (file)
index 0000000..2808672
--- /dev/null
@@ -0,0 +1,117 @@
+<?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-connector</artifactId>
+  <packaging>bundle</packaging>
+  <name>${project.artifactId}</name>
+
+  <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-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-core-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>commons.logback_settings</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>mockito-configuration</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-core-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-util</artifactId>
+    </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-data-operations</artifactId>
+          <version>0.7.0-SNAPSHOT</version>
+      </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Import-Package>*</Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <!--FIXME extract yang plugin definition into parent-->
+      <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-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java
new file mode 100644 (file)
index 0000000..ccf7512
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.mapper;
+
+import org.opendaylight.controller.netconf.mdsal.connector.MdsalNetconfOperationServiceFactory;
+
+public class NetconfMdsalMapperModule extends org.opendaylight.controller.config.yang.netconf.mdsal.mapper.AbstractNetconfMdsalMapperModule {
+    public NetconfMdsalMapperModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetconfMdsalMapperModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.netconf.mdsal.mapper.NetconfMdsalMapperModule 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 MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency(), getDomBrokerDependency());
+    }
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModuleFactory.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModuleFactory.java
new file mode 100644 (file)
index 0000000..4eb0563
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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
+ */
+
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-mdsal-mapper yang module local name: netconf-mdsal-mapper
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Jan 14 14:58:42 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.netconf.mdsal.mapper;
+public class NetconfMdsalMapperModuleFactory extends org.opendaylight.controller.config.yang.netconf.mdsal.mapper.AbstractNetconfMdsalMapperModuleFactory {
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/CurrentSchemaContext.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/CurrentSchemaContext.java
new file mode 100644 (file)
index 0000000..df671e8
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.mdsal.connector;
+
+import com.google.common.base.Preconditions;
+import java.util.concurrent.atomic.AtomicReference;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+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;
+
+    public SchemaContext getCurrentContext() {
+        Preconditions.checkState(currentContext.get() != null, "Current context not received");
+        return currentContext.get();
+    }
+
+    public CurrentSchemaContext(final SchemaService schemaService) {
+        schemaContextListenerListenerRegistration = schemaService.registerSchemaContextListener(this);
+    }
+
+    @Override
+    public void onGlobalContextUpdated(final SchemaContext schemaContext) {
+        currentContext.set(schemaContext);
+    }
+
+    @Override
+    public void close() throws Exception {
+        schemaContextListenerListenerRegistration.close();
+        currentContext.set(null);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationService.java
new file mode 100644 (file)
index 0000000..f54c5e9
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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.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);
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    // 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);
+        }
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java
new file mode 100644 (file)
index 0000000..098f25b
--- /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.mdsal.connector;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+
+public class MdsalNetconfOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable {
+
+    private final DOMDataBroker dataBroker;
+    private final CurrentSchemaContext currentSchemaContext;
+
+    public MdsalNetconfOperationServiceFactory(final SchemaService schemaService, final DOMDataBroker domDataBroker) {
+        this.currentSchemaContext = new CurrentSchemaContext(Preconditions.checkNotNull(schemaService));
+        this.dataBroker = Preconditions.checkNotNull(domDataBroker);
+    }
+
+    @Override
+    public MdsalNetconfOperationService createService(final String netconfSessionIdForReporting) {
+        return new MdsalNetconfOperationService(currentSchemaContext, netconfSessionIdForReporting, dataBroker);
+    }
+
+    @Override
+    public void close() throws Exception {
+        currentSchemaContext.close();
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/OperationProvider.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/OperationProvider.java
new file mode 100644 (file)
index 0000000..c881ae2
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.mdsal.connector;
+
+import com.google.common.collect.Sets;
+import java.util.Set;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.Commit;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.DiscardChanges;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.EditConfig;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.Lock;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.Unlock;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.get.Get;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.get.GetConfig;
+
+final class OperationProvider {
+
+    private final String netconfSessionIdForReporting;
+    private final CurrentSchemaContext schemaContext;
+    private final DOMDataBroker dataBroker;
+    private final TransactionProvider transactionProvider;
+
+    public OperationProvider(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext, final DOMDataBroker dataBroker) {
+        this.netconfSessionIdForReporting = netconfSessionIdForReporting;
+        this.schemaContext = schemaContext;
+        this.dataBroker = dataBroker;
+        this.transactionProvider = new TransactionProvider(dataBroker, netconfSessionIdForReporting);
+
+    }
+
+    Set<NetconfOperation> getOperations() {
+        return Sets.<NetconfOperation>newHashSet(
+                new Commit(netconfSessionIdForReporting, transactionProvider),
+                new DiscardChanges(netconfSessionIdForReporting, transactionProvider),
+                new EditConfig(netconfSessionIdForReporting, schemaContext, transactionProvider),
+                new Get(netconfSessionIdForReporting, schemaContext, transactionProvider),
+                new GetConfig(netconfSessionIdForReporting, schemaContext, transactionProvider),
+                new Lock(netconfSessionIdForReporting),
+                new Unlock(netconfSessionIdForReporting)
+        );
+    }
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/TransactionProvider.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/TransactionProvider.java
new file mode 100644 (file)
index 0000000..f1b214b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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.mdsal.connector;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+//TODO make a global TransactionProvider for all Netconf sessions instead of each session having one.
+public class TransactionProvider implements AutoCloseable{
+
+    private static final Logger LOG = LoggerFactory.getLogger(TransactionProvider.class);
+
+    private final DOMDataBroker dataBroker;
+
+    private DOMDataReadWriteTransaction candidateTransaction = null;
+    private DOMDataReadWriteTransaction runningTransaction = null;
+    private final List<DOMDataReadWriteTransaction> allOpenReadWriteTransactions = new ArrayList<>();
+
+    private final String netconfSessionIdForReporting;
+
+    private static final String  NO_TRANSACTION_FOUND_FOR_SESSION = "No candidateTransaction found for session ";
+
+
+    public TransactionProvider(DOMDataBroker dataBroker, String netconfSessionIdForReporting) {
+        this.dataBroker = dataBroker;
+        this.netconfSessionIdForReporting = netconfSessionIdForReporting;
+    }
+
+    @Override
+    public synchronized void close() throws Exception {
+        for (DOMDataReadWriteTransaction rwt : allOpenReadWriteTransactions) {
+            rwt.cancel();
+        }
+
+        allOpenReadWriteTransactions.clear();
+    }
+
+    public synchronized Optional<DOMDataReadWriteTransaction> getCandidateTransaction() {
+        if (candidateTransaction == null) {
+            return Optional.absent();
+        }
+
+        return Optional.of(candidateTransaction);
+    }
+
+    public synchronized DOMDataReadWriteTransaction getOrCreateTransaction() {
+        if (getCandidateTransaction().isPresent()) {
+            return getCandidateTransaction().get();
+        }
+
+        candidateTransaction = dataBroker.newReadWriteTransaction();
+        allOpenReadWriteTransactions.add(candidateTransaction);
+        return candidateTransaction;
+    }
+
+    public synchronized boolean commitTransaction() throws NetconfDocumentedException {
+        if (!getCandidateTransaction().isPresent()) {
+            throw new NetconfDocumentedException(NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting,
+                    ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
+        }
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = candidateTransaction.submit();
+        try {
+            future.checkedGet();
+        } catch (TransactionCommitFailedException e) {
+            LOG.debug("Transaction {} failed on", candidateTransaction, e);
+            throw new NetconfDocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting,
+                    ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
+        }
+        allOpenReadWriteTransactions.remove(candidateTransaction);
+        candidateTransaction = null;
+
+        return true;
+    }
+
+    public synchronized void abortTransaction() {
+        LOG.debug("Aborting current candidateTransaction");
+        Optional<DOMDataReadWriteTransaction> otx = getCandidateTransaction();
+        Preconditions.checkState(otx.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
+        candidateTransaction.cancel();
+        allOpenReadWriteTransactions.remove(candidateTransaction);
+        candidateTransaction = null;
+    }
+
+    public synchronized DOMDataReadWriteTransaction createRunningTransaction() {
+        runningTransaction = dataBroker.newReadWriteTransaction();
+        allOpenReadWriteTransactions.add(runningTransaction);
+        return runningTransaction;
+    }
+
+    public synchronized boolean commitRunningTransaction(DOMDataReadWriteTransaction tx) throws NetconfDocumentedException {
+        allOpenReadWriteTransactions.remove(tx);
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
+        try {
+            future.checkedGet();
+        } catch (TransactionCommitFailedException e) {
+            LOG.debug("Transaction {} failed on", tx, e);
+            throw new NetconfDocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting,
+                    ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
+        }
+
+        return true;
+    }
+
+    public synchronized void abortRunningTransaction(DOMDataReadWriteTransaction tx) {
+        LOG.debug("Aborting current running Transaction");
+        Preconditions.checkState(runningTransaction != null, NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
+        tx.cancel();
+        allOpenReadWriteTransactions.remove(tx);
+    }
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Commit.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Commit.java
new file mode 100644 (file)
index 0000000..15396cf
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.mdsal.connector.ops;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class Commit extends AbstractLastNetconfOperation{
+
+    private static final Logger LOG = LoggerFactory.getLogger(Commit.class);
+
+    private static final String OPERATION_NAME = "commit";
+    private final TransactionProvider transactionProvider;
+
+    public Commit(final String netconfSessionIdForReporting, final TransactionProvider transactionProvider) {
+        super(netconfSessionIdForReporting);
+        this.transactionProvider = transactionProvider;
+
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+
+        boolean commitStatus = transactionProvider.commitTransaction();
+        LOG.trace("Transaction commited succesfuly", commitStatus);
+
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+
+}
@@ -1,16 +1,13 @@
 /*
- * 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.cluster.raft.base.messages;
+package org.opendaylight.controller.netconf.mdsal.connector.ops;
 
-/**
- * Internal message by Leader to initiate an install snapshot
- */
-public class InitiateInstallSnapshot {
+public enum Datastore {
+    candidate, running
 }
-
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/DiscardChanges.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/DiscardChanges.java
new file mode 100644 (file)
index 0000000..36f6d8e
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.mdsal.connector.ops;
+
+import com.google.common.base.Optional;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class DiscardChanges extends AbstractLastNetconfOperation{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DiscardChanges.class);
+
+    private static final String OPERATION_NAME = "discard-changes";
+
+    private final TransactionProvider transactionProvider;
+
+    public DiscardChanges(final String netconfSessionIdForReporting, final TransactionProvider transactionProvider) {
+        super(netconfSessionIdForReporting);
+        this.transactionProvider = transactionProvider;
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        operationElement.getOnlyChildElement(OPERATION_NAME);
+
+        try {
+            transactionProvider.abortTransaction();
+        } catch (IllegalStateException e) {
+            LOG.warn("Abort failed ", e);
+            final Map<String, String> errorInfo = new HashMap<>();
+            errorInfo
+                    .put(ErrorTag.operation_failed.name(),
+                            "Operation failed. Use 'get-config' or 'edit-config' before triggering 'discard-changes' operation");
+            throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+                    ErrorSeverity.error, errorInfo);
+        }
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java
new file mode 100644 (file)
index 0000000..09be416
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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.mdsal.connector.ops;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+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;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
+import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.operations.DataModificationException;
+import org.opendaylight.yangtools.yang.data.operations.DataModificationException.DataExistsException;
+import org.opendaylight.yangtools.yang.data.operations.DataModificationException.DataMissingException;
+import org.opendaylight.yangtools.yang.data.operations.DataOperations;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class EditConfig extends AbstractLastNetconfOperation {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EditConfig.class);
+
+    private static final String OPERATION_NAME = "edit-config";
+    private static final String CONFIG_KEY = "config";
+
+    private final CurrentSchemaContext schemaContext;
+    private final TransactionProvider transactionProvider;
+
+    public EditConfig(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext, final TransactionProvider transactionProvider) {
+        super(netconfSessionIdForReporting);
+        this.schemaContext = schemaContext;
+        this.transactionProvider = transactionProvider;
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        final XmlElement configElement = getConfigElement(operationElement);
+
+        for (XmlElement element : configElement.getChildElements()) {
+            final String ns = element.getNamespace();
+            final DataSchemaNode schemaNode = getSchemaNodeFromNamespace(ns, element).get();
+            YangInstanceIdentifier ident = YangInstanceIdentifier.of(schemaNode.getQName());
+
+            final NormalizedNode storedNode = readStoredNode(LogicalDatastoreType.CONFIGURATION, ident);
+            try {
+                final Optional<NormalizedNode<?,?>> newNode = modifyNode(schemaNode, element, storedNode);
+                final DOMDataReadWriteTransaction rwTx = transactionProvider.getOrCreateTransaction();
+                if (newNode.isPresent()) {
+                    rwTx.put(LogicalDatastoreType.CONFIGURATION, ident, newNode.get());
+                } else {
+                    rwTx.delete(LogicalDatastoreType.CONFIGURATION, ident);
+                }
+            } catch (final DataModificationException e) {
+                if (e instanceof DataExistsException) {
+                    throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_exists, ErrorSeverity.error);
+                } else if (e instanceof DataMissingException) {
+                    throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_missing, ErrorSeverity.error);
+                } else {
+                    //should never happen, since in edit-config only the 2 previous cases can happen
+                    throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.operation_failed, ErrorSeverity.error);
+                }
+            }
+        }
+
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+    }
+
+    private NormalizedNode readStoredNode(final LogicalDatastoreType logicalDatastoreType, final YangInstanceIdentifier path) throws NetconfDocumentedException{
+        final  DOMDataReadWriteTransaction rwTx = transactionProvider.getOrCreateTransaction();
+        final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readFuture = rwTx.read(logicalDatastoreType, path);
+        try {
+            if (readFuture.checkedGet().isPresent()) {
+                final NormalizedNode node = readFuture.checkedGet().get();
+                return node;
+            } else {
+                LOG.warn("Unable to read node : {} from {} datastore", path, logicalDatastoreType);
+            }
+        } catch (final ReadFailedException e) {
+            //only log this since DataOperations.modify will handle throwing an exception or writing the node.
+            LOG.warn("Unable to read stored data: {}", path, e);
+        }
+
+        //we can return null here since DataOperations.modify handles null as input
+        return null;
+    }
+
+    private Optional<DataSchemaNode> getSchemaNodeFromNamespace(final String namespace, final XmlElement element){
+        Optional<DataSchemaNode> dataSchemaNode = Optional.absent();
+        try {
+            //returns module with newest revision since findModuleByNamespace returns a set of modules and we only need the newest one
+            final Module module = schemaContext.getCurrentContext().findModuleByNamespaceAndRevision(new URI(namespace), null);
+            dataSchemaNode = Optional.of(module.getDataChildByName(element.getName()));
+        } catch (URISyntaxException e) {
+            LOG.debug("Unable to create URI for namespace : {}", namespace);
+        }
+
+        return dataSchemaNode;
+    }
+
+    private Optional<NormalizedNode<?, ?>> modifyNode(final DataSchemaNode schemaNode, final XmlElement element, final NormalizedNode storedNode) throws DataModificationException{
+        if (schemaNode instanceof ContainerSchemaNode) {
+            final ContainerNode modifiedNode =
+                    DomToNormalizedNodeParserFactory
+                            .getInstance(DomUtils.defaultValueCodecProvider())
+                            .getContainerNodeParser()
+                            .parse(Collections.singletonList(element.getDomElement()), (ContainerSchemaNode) schemaNode);
+
+            final Optional<ContainerNode> oNode = DataOperations.modify((ContainerSchemaNode) schemaNode, (ContainerNode) storedNode, modifiedNode);
+            if (!oNode.isPresent()) {
+                return Optional.absent();
+            }
+
+            final NormalizedNode<?,?> node = oNode.get();
+            return Optional.<NormalizedNode<?,?>>of(node);
+        } else if (schemaNode instanceof ListSchemaNode) {
+            final MapNode modifiedNode =
+                DomToNormalizedNodeParserFactory
+                        .getInstance(DomUtils.defaultValueCodecProvider())
+                        .getMapNodeParser()
+                        .parse(Collections.singletonList(element.getDomElement()), (ListSchemaNode) schemaNode);
+
+            final Optional<MapNode> oNode = DataOperations.modify((ListSchemaNode) schemaNode, (MapNode) storedNode, modifiedNode);
+            if (!oNode.isPresent()) {
+                return Optional.absent();
+            }
+
+            final NormalizedNode<?, ?> node = oNode.get();
+            return Optional.<NormalizedNode<?,?>>of(node);
+        } else {
+            //this should never happen since edit-config on any other node type should not be possible nor makes sense
+            LOG.debug("DataNode from module is not ContainerSchemaNode nor ListSchemaNode, aborting..");
+            return Optional.absent();
+        }
+
+    }
+
+    private XmlElement getConfigElement(final XmlElement operationElement) throws NetconfDocumentedException{
+        final Optional<XmlElement> configChildNode = operationElement.getOnlyChildElementOptionally(CONFIG_KEY);
+        if (!configChildNode.isPresent()) {
+            throw new NetconfDocumentedException("Can't get child element with name: " + CONFIG_KEY,
+                    ErrorType.application,
+                    ErrorTag.unknown_element,
+                    ErrorSeverity.error);
+        }
+
+        return configChildNode.get();
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Lock.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Lock.java
new file mode 100644 (file)
index 0000000..db912c5
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.mdsal.connector.ops;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
+import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class Lock extends AbstractLastNetconfOperation{
+
+    private static final Logger LOG = LoggerFactory.getLogger(Lock.class);
+
+    private static final String OPERATION_NAME = "lock";
+    private static final String TARGET_KEY = "target";
+
+    public Lock(final String netconfSessionIdForReporting) {
+        super(netconfSessionIdForReporting);
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        final Datastore targetDatastore = extractTargetParameter(operationElement);
+        if (targetDatastore == Datastore.candidate) {
+            LOG.debug("Locking candidate datastore on session: {}", getNetconfSessionIdForReporting());
+            return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+        }
+
+        throw new NetconfDocumentedException("Unable to lock " + targetDatastore + " datastore", NetconfDocumentedException.ErrorType.application,
+                NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+    }
+
+    static Datastore extractTargetParameter(final XmlElement operationElement) throws NetconfDocumentedException {
+        final XmlElement targetChildNode;
+        try {
+            final XmlElement targetElement = operationElement.getOnlyChildElementWithSameNamespace(TARGET_KEY);
+            targetChildNode = targetElement.getOnlyChildElementWithSameNamespace();
+        } catch (final MissingNameSpaceException | UnexpectedNamespaceException e) {
+            LOG.trace("Can't get only child element with same namespace", e);
+            throw NetconfDocumentedException.wrap(e);
+        }
+
+        return Datastore.valueOf(targetChildNode.getName());
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Unlock.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/Unlock.java
new file mode 100644 (file)
index 0000000..2dd2663
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.mdsal.connector.ops;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class Unlock extends AbstractLastNetconfOperation{
+
+    private static final Logger LOG = LoggerFactory.getLogger(Unlock.class);
+
+    private static final String OPERATION_NAME = "unlock";
+    private static final String TARGET_KEY = "target";
+
+    public Unlock(final String netconfSessionIdForReporting) {
+        super(netconfSessionIdForReporting);
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        final Datastore targetDatastore = Lock.extractTargetParameter(operationElement);
+        if (targetDatastore == Datastore.candidate) {
+            LOG.debug("Unlocking candidate datastore on session: {}", getNetconfSessionIdForReporting());
+            return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+        }
+
+        throw new NetconfDocumentedException("Unable to unlock " + targetDatastore + " datastore", NetconfDocumentedException.ErrorType.application,
+                NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/AbstractGet.java
new file mode 100644 (file)
index 0000000..e0c0044
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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.mdsal.connector.ops.get;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+import java.io.IOException;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMResult;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+public abstract class AbstractGet extends AbstractLastNetconfOperation {
+
+    protected static final YangInstanceIdentifier ROOT = YangInstanceIdentifier.builder().build();
+
+    protected final CurrentSchemaContext schemaContext;
+
+
+    public AbstractGet(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) {
+        super(netconfSessionIdForReporting);
+        this.schemaContext = schemaContext;
+    }
+
+    private static final XMLOutputFactory XML_OUTPUT_FACTORY;
+
+    static {
+        XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
+        XML_OUTPUT_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+    }
+
+    protected Node transformNormalizedNode(final Document document, final NormalizedNode<?, ?> data, final YangInstanceIdentifier dataRoot) {
+//        boolean isDataRoot = true;
+
+        final DOMResult result = new DOMResult(document.createElement(XmlNetconfConstants.DATA_KEY));
+
+        final XMLStreamWriter xmlWriter = getXmlStreamWriter(result);
+
+        final NormalizedNodeStreamWriter nnStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
+                schemaContext.getCurrentContext(), getSchemaPath(dataRoot));
+
+        final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(nnStreamWriter);
+
+//        if (isDataRoot) {
+        writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
+//        } else {
+//            if (data instanceof MapEntryNode) {
+//                // Restconf allows returning one list item. We need to wrap it
+//                // in map node in order to serialize it properly
+//                data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).addChild((MapEntryNode) data).build();
+//            }
+//            nnWriter.write(data);
+//            nnWriter.flush();
+//        }
+        return result.getNode();
+    }
+
+    private XMLStreamWriter getXmlStreamWriter(final DOMResult result) {
+        try {
+            return XML_OUTPUT_FACTORY.createXMLStreamWriter(result);
+        } catch (final XMLStreamException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static final Function<PathArgument, QName> PATH_ARG_TO_QNAME = new Function<YangInstanceIdentifier.PathArgument, QName>() {
+        @Override
+        public QName apply(final YangInstanceIdentifier.PathArgument input) {
+            return input.getNodeType();
+        }
+    };
+
+    private SchemaPath getSchemaPath(final YangInstanceIdentifier dataRoot) {
+        return SchemaPath.create(Iterables.transform(dataRoot.getPathArguments(), PATH_ARG_TO_QNAME), dataRoot.equals(ROOT));
+    }
+
+    // TODO this code is located in Restconf already
+    private void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter, final ContainerNode data) {
+        try {
+            final QName name = SchemaContext.NAME;
+            for (final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
+                nnWriter.write(child);
+            }
+            nnWriter.flush();
+            xmlWriter.flush();
+        } catch (XMLStreamException | IOException e) {
+            Throwables.propagate(e);
+        }
+    }
+
+    protected static final class GetConfigExecution {
+        private final Datastore datastore;
+
+        public GetConfigExecution(final Datastore datastore) {
+            this.datastore = datastore;
+        }
+
+        public Datastore getDatastore() {
+            return datastore;
+        }
+
+        static GetConfigExecution fromXml(final XmlElement xml, final String operationName) throws NetconfDocumentedException {
+            try {
+                validateInputRpc(xml, operationName);
+            } catch (final NetconfDocumentedException e) {
+                throw new NetconfDocumentedException("Incorrect RPC: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
+            }
+
+            final Datastore sourceDatastore;
+            try {
+                sourceDatastore = parseSource(xml);
+            } catch (final NetconfDocumentedException e) {
+                throw new NetconfDocumentedException("Get-config source attribute error: " + e.getMessage(), e.getErrorType(), e.getErrorTag(), e.getErrorSeverity(), e.getErrorInfo());
+            }
+
+            // Add filter
+
+            return new GetConfigExecution(sourceDatastore);
+        }
+
+        private static Datastore parseSource(final XmlElement xml) throws NetconfDocumentedException {
+            final Datastore sourceDatastore;
+            final XmlElement sourceElement = xml.getOnlyChildElement(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;
+        }
+
+        private static void validateInputRpc(final XmlElement xml, String operationName) throws NetconfDocumentedException{
+            xml.checkName(operationName);
+            xml.checkNamespace(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+        }
+    }
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/Get.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/Get.java
new file mode 100644 (file)
index 0000000..a2b2fbb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.mdsal.connector.ops.get;
+
+import com.google.common.base.Optional;
+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;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
+import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+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 org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class Get extends AbstractGet {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Get.class);
+
+    private static final String OPERATION_NAME = "get";
+
+    private final TransactionProvider transactionProvider;
+
+    public Get(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext, final TransactionProvider transactionProvider) {
+        super(netconfSessionIdForReporting, schemaContext);
+        this.transactionProvider = transactionProvider;
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {
+        GetConfigExecution getConfigExecution = null;
+        try {
+            getConfigExecution = GetConfigExecution.fromXml(operationElement, OPERATION_NAME);
+
+        } catch (final NetconfDocumentedException e) {
+            LOG.warn("Get request processing failed on session: {}", getNetconfSessionIdForReporting(), e);
+            throw e;
+        }
+
+        final YangInstanceIdentifier dataRoot = ROOT;
+        DOMDataReadWriteTransaction rwTx = getTransaction(getConfigExecution.getDatastore());
+        try {
+            final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = rwTx.read(LogicalDatastoreType.OPERATIONAL, dataRoot).checkedGet();
+            if (getConfigExecution.getDatastore() == Datastore.running) {
+                transactionProvider.abortRunningTransaction(rwTx);
+                rwTx = null;
+            }
+            return (Element) transformNormalizedNode(document, normalizedNodeOptional.get(), dataRoot);
+        } catch (ReadFailedException e) {
+            LOG.warn("Unable to read data: {}", dataRoot, e);
+            throw new IllegalStateException("Unable to read data " + dataRoot, e);
+        }
+    }
+
+    private DOMDataReadWriteTransaction getTransaction(Datastore datastore) throws NetconfDocumentedException{
+        if (datastore == Datastore.candidate) {
+            return transactionProvider.getOrCreateTransaction();
+        } else if (datastore == Datastore.running) {
+            return transactionProvider.createRunningTransaction();
+        }
+        throw new NetconfDocumentedException("Incorrect Datastore: ", ErrorType.protocol, ErrorTag.bad_element, ErrorSeverity.error);
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/GetConfig.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/get/GetConfig.java
new file mode 100644 (file)
index 0000000..b56bcc7
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.mdsal.connector.ops.get;
+
+import com.google.common.base.Optional;
+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;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext;
+import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider;
+import org.opendaylight.controller.netconf.mdsal.connector.ops.Datastore;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+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 org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class GetConfig extends AbstractGet {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GetConfig.class);
+
+    private static final String OPERATION_NAME = "get-config";
+
+    private final TransactionProvider transactionProvider;
+
+    public GetConfig(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext, final TransactionProvider transactionProvider) {
+        super(netconfSessionIdForReporting, schemaContext);
+        this.transactionProvider = transactionProvider;
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(Document document, XmlElement operationElement) throws NetconfDocumentedException {
+        GetConfigExecution getConfigExecution = null;
+        try {
+            getConfigExecution = GetConfigExecution.fromXml(operationElement, OPERATION_NAME);
+
+        } catch (final NetconfDocumentedException e) {
+            LOG.warn("Get request processing failed on session: {}", getNetconfSessionIdForReporting(), e);
+            throw e;
+        }
+
+        final YangInstanceIdentifier dataRoot = ROOT;
+        DOMDataReadWriteTransaction rwTx = getTransaction(getConfigExecution.getDatastore());
+        try {
+            final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = rwTx.read(LogicalDatastoreType.CONFIGURATION, dataRoot).checkedGet();
+            if (getConfigExecution.getDatastore() == Datastore.running) {
+                transactionProvider.abortRunningTransaction(rwTx);
+                rwTx = null;
+            }
+            return (Element) transformNormalizedNode(document, normalizedNodeOptional.get(), dataRoot);
+        } catch (ReadFailedException e) {
+            LOG.warn("Unable to read data: {}", dataRoot, e);
+            throw new IllegalStateException("Unable to read data " + dataRoot, e);
+        }
+    }
+
+    private DOMDataReadWriteTransaction getTransaction(Datastore datastore) throws NetconfDocumentedException{
+        if (datastore == Datastore.candidate) {
+            return transactionProvider.getOrCreateTransaction();
+        } else if (datastore == Datastore.running) {
+            return transactionProvider.createRunningTransaction();
+        }
+        throw new NetconfDocumentedException("Incorrect Datastore: ", ErrorType.protocol, ErrorTag.bad_element, ErrorSeverity.error);
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+
+}
diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang b/opendaylight/netconf/mdsal-netconf-connector/src/main/yang/netconf-mdsal-mapper.yang
new file mode 100644 (file)
index 0000000..b1d0410
--- /dev/null
@@ -0,0 +1,50 @@
+module netconf-mdsal-mapper {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper";
+    prefix "nmm";
+
+    import netconf-northbound-mapper { prefix nnm; revision-date 2015-01-14; }
+    import opendaylight-md-sal-dom { prefix md-sal-dom; revision-date 2013-10-28; }
+    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 mapper implementation";
+
+    revision "2015-01-14" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-mdsal-mapper {
+        base config:module-type;
+        config:provided-service nnm:netconf-northbound-mapper;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netconf-mdsal-mapper {
+            when "/config:modules/config:module/config:type = 'netconf-mdsal-mapper'";
+
+            container root-schema-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory false;
+                        config:required-identity md-sal-dom:schema-service;
+                    }
+                }
+            }
+
+            container dom-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory false;
+                        config:required-identity md-sal-dom:dom-async-data-broker;
+                    }
+                }
+            }
+        }
+    }
+
+}
index 18bbce4e3028e1a23d137f8a76602493fa1abf36..965747c2ea2c205f9d45bacfed24d4a2e76d5826 100644 (file)
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <configuration>
-          <instructions>
-            <Export-Package>org.opendaylight.controller.netconf.api,
-                            org.opendaylight.controller.netconf.api.jmx,
-                            org.opendaylight.controller.netconf.api.xml,
-                            org.opendaylight.controller.netconf.api.monitoring,</Export-Package>
-          </instructions>
-        </configuration>
       </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>
 
diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfServerDispatcher.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfServerDispatcher.java
new file mode 100644 (file)
index 0000000..6bf21c1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.local.LocalAddress;
+import java.net.InetSocketAddress;
+
+public interface NetconfServerDispatcher {
+
+    ChannelFuture createServer(InetSocketAddress address);
+
+    ChannelFuture createLocalServer(LocalAddress address);
+}
diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/util/NetconfConstants.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/util/NetconfConstants.java
new file mode 100644 (file)
index 0000000..b9c4dca
--- /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.util;
+
+public final class NetconfConstants {
+    /*
+     * TODO define marker interface in mapping-api that the serviceFactories in cofing subsystem
+     * will implement so we can check for services with instanceof instead of constants
+     */
+    public static final String SERVICE_NAME = "name";
+    public static final String CONFIG_NETCONF_CONNECTOR = "config-netconf-connector";
+    public static final String NETCONF_MONITORING = "ietf-netconf-monitoring";
+}
diff --git a/opendaylight/netconf/netconf-api/src/main/yang/netconf-northbound.yang b/opendaylight/netconf/netconf-api/src/main/yang/netconf-northbound.yang
new file mode 100644 (file)
index 0000000..f775da9
--- /dev/null
@@ -0,0 +1,22 @@
+module netconf-northbound {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound";
+    prefix "nn";
+
+    import config { prefix config; revision-date 2013-04-05; }
+
+    description
+        "This module contains the base YANG definitions for
+         netconf northbound server API";
+
+    revision "2015-01-14" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-server-dispatcher {
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.netconf.api.NetconfServerDispatcher";
+    }
+
+}
\ No newline at end of file
index 3487aa7be35975bf947b5eda372fd3e1ec964f85..12489339154075ae01545c2083c531cfd6e2f3e2 100644 (file)
                 <artifactId>netconf-connector-config</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>netconf-mdsal-config</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>mdsal-netconf-connector</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>netconf-impl</artifactId>
index f81a332ab6e8a2832b62e0e9a7ff164b1488ab46..06a5e6514956329a674e9b19b028840a9d192f9c 100644 (file)
             <name>global-netconf-processing-executor-threadfactory</name>
           </threadFactory>
         </module>
+
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled">prefix:threadpool-scheduled</type>
+          <name>global-netconf-ssh-scheduled-executor</name>
+          <max-thread-count xmlns="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled">8</max-thread-count>
+
+          <threadFactory xmlns="urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled">
+            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">prefix:threadfactory</type>
+            <name>global-netconf-processing-executor-threadfactory</name>
+          </threadFactory>
+        </module>
       </modules>
 
       <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
             <name>global-netconf-processing-executor</name>
             <provider>/modules/module[type='threadpool-flexible'][name='global-netconf-processing-executor']</provider>
           </instance>
+            <instance>
+            <name>global-netconf-ssh-scheduled-executor</name>
+            <provider>/modules/module[type='threadpool-scheduled'][name='global-netconf-ssh-scheduled-executor']</provider>
+          </instance>
         </service>
       </services>
 
@@ -81,5 +96,6 @@
       <capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:client:dispatcher?module=odl-netconfig-client-cfg&amp;revision=2014-04-08</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&amp;revision=2013-04-05</capability>
       <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:flexible?module=threadpool-impl-flexible&amp;revision=2013-12-01</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled?module=threadpool-impl-scheduled&amp;revision=2013-12-01</capability>
   </required-capabilities>
 </snapshot>
index 2bd919df947125971ccdf843ab64d87490881879..28c61b994640ed9229795fe150c7b7c45628fcd9 100644 (file)
@@ -42,7 +42,7 @@
             <name>global-netconf-processing-executor</name>
           </processing-executor>
         </module>
-      </modules>
+        </modules>
     </data>
   </configuration>
   <required-capabilities>
index 310073fc72e537330c37885fcd7f75748a327b8d..6f19731f016a36f814029f46288c1532666fc70d 100644 (file)
         <configuration>
           <instructions>
             <Bundle-Activator>org.opendaylight.controller.netconf.impl.osgi.NetconfImplActivator</Bundle-Activator>
+            <Export-Package>org.opendaylight.controller.netconf.impl.*</Export-Package>
           </instructions>
         </configuration>
       </plugin>
           </execution>
         </executions>
       </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>
 
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerDispatcherModule.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerDispatcherModule.java
new file mode 100644 (file)
index 0000000..e64620d
--- /dev/null
@@ -0,0 +1,60 @@
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+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.mapping.api.NetconfOperationServiceFactory;
+
+public class NetconfServerDispatcherModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerDispatcherModule {
+    public NetconfServerDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetconfServerDispatcherModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.netconf.northbound.impl.NetconfServerDispatcherModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        JmxAttributeValidationException.checkCondition(getConnectionTimeoutMillis() > 0, "Invalid connection timeout", connectionTimeoutMillisJmxAttribute);
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+
+        final NetconfOperationServiceFactoryListenerImpl aggregatedOpProvider = getAggregatedOpProvider();
+        final SessionMonitoringService monitoringService = startMonitoringService(aggregatedOpProvider);
+        final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
+                getTimerDependency(), aggregatedOpProvider, new SessionIdProvider(), getConnectionTimeoutMillis(), CommitNotifier.NoopCommitNotifier.getInstance(), monitoringService);
+        final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
+                serverNegotiatorFactory);
+
+        return new NetconfServerDispatcherImpl(serverChannelInitializer, getBossThreadGroupDependency(), getWorkerThreadGroupDependency()) {
+
+            @Override
+            public void close() {
+                // NOOP, close should not be present here, the deprecated method closes injected evet loop groups
+            }
+        };
+
+    }
+
+    private NetconfMonitoringServiceImpl startMonitoringService(final NetconfOperationServiceFactoryListenerImpl netconfOperationProvider) {
+        return new NetconfMonitoringServiceImpl(netconfOperationProvider);
+    }
+
+    private NetconfOperationServiceFactoryListenerImpl getAggregatedOpProvider() {
+        final NetconfOperationServiceFactoryListenerImpl netconfOperationProvider = new NetconfOperationServiceFactoryListenerImpl();
+        for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getMappersDependency()) {
+            netconfOperationProvider.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
+        }
+        return netconfOperationProvider;
+    }
+
+
+}
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerDispatcherModuleFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/config/yang/config/netconf/northbound/impl/NetconfServerDispatcherModuleFactory.java
new file mode 100644 (file)
index 0000000..de44cad
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-northbound-impl yang module local name: netconf-server-dispatcher-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Feb 12 11:32:29 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 NetconfServerDispatcherModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerDispatcherModuleFactory {
+
+}
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/CommitNotifier.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/CommitNotifier.java
new file mode 100644 (file)
index 0000000..d9f8e34
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+import java.util.Set;
+import org.w3c.dom.Element;
+
+public interface CommitNotifier {
+    void sendCommitNotification(String message, Element cfgSnapshot, Set<String> capabilities);
+
+    public static final class NoopCommitNotifier implements CommitNotifier {
+
+        private static final CommitNotifier INSTANCE = new NoopCommitNotifier();
+
+        private NoopCommitNotifier() {}
+
+        public static CommitNotifier getInstance() {
+            return INSTANCE;
+        }
+
+        @Override
+        public void sendCommitNotification(final String message, final Element cfgSnapshot, final Set<String> capabilities) {
+            // NOOP
+        }
+    }
+}
index ab37bac683829a95cc4e78ec24bcfb56c584faf1..88ff928c515af00eb22a7b03d8075f23aebc9933 100644 (file)
@@ -24,7 +24,7 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Element;
 
 public class DefaultCommitNotificationProducer extends NotificationBroadcasterSupport implements
-        DefaultCommitOperationMXBean, AutoCloseable {
+        DefaultCommitOperationMXBean, AutoCloseable, CommitNotifier {
 
     private static final Logger LOG = LoggerFactory.getLogger(DefaultCommitNotificationProducer.class);
 
@@ -46,6 +46,7 @@ public class DefaultCommitNotificationProducer extends NotificationBroadcasterSu
         }
     }
 
+    @Override
     public void sendCommitNotification(String message, Element cfgSnapshot, Set<String> capabilities) {
         CommitJMXNotification notif = NetconfJMXNotification.afterCommit(this, message, cfgSnapshot, capabilities);
         LOG.debug("Notification about commit {} sent", notif);
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.annotations.VisibleForTesting;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
@@ -18,23 +17,23 @@ import io.netty.channel.local.LocalServerChannel;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.concurrent.Promise;
 import java.net.InetSocketAddress;
+import org.opendaylight.controller.netconf.api.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler;
 import org.opendaylight.controller.netconf.nettyutil.AbstractChannelInitializer;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
 
-public class NetconfServerDispatcher extends AbstractDispatcher<NetconfServerSession, NetconfServerSessionListener> {
+public class NetconfServerDispatcherImpl extends AbstractDispatcher<NetconfServerSession, NetconfServerSessionListener> implements NetconfServerDispatcher {
 
     private final ServerChannelInitializer initializer;
 
-    public NetconfServerDispatcher(ServerChannelInitializer serverChannelInitializer, EventLoopGroup bossGroup,
-            EventLoopGroup workerGroup) {
+    public NetconfServerDispatcherImpl(ServerChannelInitializer serverChannelInitializer, EventLoopGroup bossGroup,
+                                       EventLoopGroup workerGroup) {
         super(bossGroup, workerGroup);
         this.initializer = serverChannelInitializer;
     }
 
-    @VisibleForTesting
+    @Override
     public ChannelFuture createServer(InetSocketAddress address) {
-
         return super.createServer(address, new PipelineInitializer<NetconfServerSession>() {
             @Override
             public void initializeChannel(final SocketChannel ch, final Promise<NetconfServerSession> promise) {
@@ -43,6 +42,7 @@ public class NetconfServerDispatcher extends AbstractDispatcher<NetconfServerSes
         });
     }
 
+    @Override
     public ChannelFuture createLocalServer(LocalAddress address) {
         return super.createServer(address, LocalServerChannel.class, new ChannelPipelineInitializer<LocalChannel, NetconfServerSession>() {
             @Override
index 0537942487296c19d99ffa2dcc10cea4a64bd6af..604cc5f55b94a4d8a41c00efff669ead36a94af3 100644 (file)
@@ -17,12 +17,12 @@ import org.opendaylight.protocol.framework.SessionListenerFactory;
 
 public class NetconfServerSessionListenerFactory implements SessionListenerFactory<NetconfServerSessionListener> {
 
-    private final DefaultCommitNotificationProducer commitNotifier;
+    private final CommitNotifier commitNotifier;
     private final SessionMonitoringService monitor;
     private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
     private final CapabilityProvider capabilityProvider;
 
-    public NetconfServerSessionListenerFactory(final DefaultCommitNotificationProducer commitNotifier,
+    public NetconfServerSessionListenerFactory(final CommitNotifier commitNotifier,
                                                final SessionMonitoringService monitor,
                                                final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
                                                final CapabilityProvider capabilityProvider) {
index 34f4f0e653137235a22e917a99224bb96f138ca7..451c066b772f5d705c0904fadd183ef48926a683 100644 (file)
@@ -44,7 +44,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     private final SessionIdProvider idProvider;
     private final NetconfOperationProvider netconfOperationProvider;
     private final long connectionTimeoutMillis;
-    private final DefaultCommitNotificationProducer commitNotificationProducer;
+    private final CommitNotifier commitNotificationProducer;
     private final SessionMonitoringService monitoringService;
     private static final Logger LOG = LoggerFactory.getLogger(NetconfServerSessionNegotiatorFactory.class);
     private final Set<String> baseCapabilities;
@@ -52,7 +52,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     // TODO too many params, refactor
     public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
                                                  SessionIdProvider idProvider, long connectionTimeoutMillis,
-                                                 DefaultCommitNotificationProducer commitNot,
+                                                 CommitNotifier commitNot,
                                                  SessionMonitoringService monitoringService) {
         this(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, commitNot, monitoringService, DEFAULT_BASE_CAPABILITIES);
     }
@@ -60,7 +60,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     // TODO too many params, refactor
     public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
                                                  SessionIdProvider idProvider, long connectionTimeoutMillis,
-                                                 DefaultCommitNotificationProducer commitNot,
+                                                 CommitNotifier commitNot,
                                                  SessionMonitoringService monitoringService, Set<String> baseCapabilities) {
         this.timer = timer;
         this.netconfOperationProvider = netconfOperationProvider;
index fbe855f8bebddcb8aeffd728b553ce112fc50f6c..742255f973ca4eaebf79958e4c67d251e3a1b922 100644 (file)
@@ -12,7 +12,7 @@ import com.google.common.base.Preconditions;
 import java.io.InputStream;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+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;
@@ -31,11 +31,11 @@ public class DefaultCommit extends AbstractNetconfOperation {
 
     private static final String NOTIFY_ATTR = "notify";
 
-    private final DefaultCommitNotificationProducer notificationProducer;
+    private final CommitNotifier notificationProducer;
     private final CapabilityProvider cap;
     private final NetconfOperationRouter operationRouter;
 
-    public DefaultCommit(DefaultCommitNotificationProducer notifier, CapabilityProvider cap,
+    public DefaultCommit(CommitNotifier notifier, CapabilityProvider cap,
                          String netconfSessionIdForReporting, NetconfOperationRouter netconfOperationRouter) {
         super(netconfSessionIdForReporting);
         this.notificationProducer = notifier;
index 27423c09b7fb732e0bd6364dc3469efd2c13f884..a55e32a954ad99a85521e11f541567c962a20b84 100644 (file)
@@ -16,7 +16,7 @@ import java.util.Hashtable;
 import java.util.concurrent.TimeUnit;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
+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;
@@ -57,9 +57,9 @@ public class NetconfImplActivator implements BundleActivator {
 
         eventLoopGroup = new NioEventLoopGroup();
 
-        NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
+        NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
                 serverNegotiatorFactory);
-        NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
+        NetconfServerDispatcherImpl dispatch = new NetconfServerDispatcherImpl(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
 
         LocalAddress address = NetconfConfigUtil.getNetconfLocalAddress();
         LOG.trace("Starting local netconf server at {}", address);
index 2178d4eedffb1a280b8fa6bfe49a489d8be72138..c8fa3417473219cc284e5a7891726c52c58ad344 100644 (file)
@@ -17,7 +17,7 @@ import java.util.NavigableMap;
 import java.util.Set;
 import java.util.TreeMap;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+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;
@@ -44,7 +44,7 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
     private final Collection<NetconfOperation> allNetconfOperations;
 
     public NetconfOperationRouterImpl(final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot, final CapabilityProvider capabilityProvider,
-            final DefaultCommitNotificationProducer commitNotifier) {
+            final CommitNotifier commitNotifier) {
         this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot);
 
         final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting();
index c1d9317c294ca96938dbd0ccec843eb7d5991d0f..9a077a6130bb630cf9fdf5923e78a46eaaf6933b 100644 (file)
@@ -7,6 +7,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.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -24,15 +25,23 @@ class NetconfOperationServiceFactoryTracker extends
 
     @Override
     public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
-        NetconfOperationServiceFactory netconfOperationServiceFactory = super.addingService(reference);
-        factoriesListener.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
-        return netconfOperationServiceFactory;
+        Object property = reference.getProperty(NetconfConstants.SERVICE_NAME);
+        if (property != null
+                && (property.equals(NetconfConstants.CONFIG_NETCONF_CONNECTOR)
+                || property.equals(NetconfConstants.NETCONF_MONITORING))) {
+            NetconfOperationServiceFactory netconfOperationServiceFactory = super.addingService(reference);
+            factoriesListener.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
+            return netconfOperationServiceFactory;
+        }
+
+        return null;
     }
 
     @Override
     public void removedService(ServiceReference<NetconfOperationServiceFactory> reference,
             NetconfOperationServiceFactory netconfOperationServiceFactory) {
-        factoriesListener.onRemoveNetconfOperationServiceFactory(netconfOperationServiceFactory);
+        if (netconfOperationServiceFactory != null)
+            factoriesListener.onRemoveNetconfOperationServiceFactory(netconfOperationServiceFactory);
     }
 
 }
diff --git a/opendaylight/netconf/netconf-impl/src/main/yang/netconf-northbound-impl.yang b/opendaylight/netconf/netconf-impl/src/main/yang/netconf-northbound-impl.yang
new file mode 100644 (file)
index 0000000..6ca0a77
--- /dev/null
@@ -0,0 +1,80 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module netconf-northbound-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl";
+    prefix "cfg-net-s-i";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import netconf-northbound-mapper { prefix nnm; revision-date 2015-01-14; }
+    import netconf-northbound { prefix nn; revision-date 2015-01-14; }
+    import netty {prefix netty; }
+
+    description
+        "This module contains the base YANG definitions for
+        netconf-server-dispatcher implementation.
+
+        Copyright (c)2013 Cisco Systems, Inc. All rights reserved.;
+
+        This program and the accompanying materials are made available
+        under the terms of the Eclipse Public License v1.0 which
+        accompanies this distribution, and is available at
+        http://www.eclipse.org/legal/epl-v10.html";
+
+    revision "2015-01-12" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-server-dispatcher-impl {
+            base config:module-type;
+            config:provided-service nn:netconf-server-dispatcher;
+            config:java-name-prefix NetconfServerDispatcher;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netconf-server-dispatcher-impl {
+            when "/config:modules/config:module/config:type = 'netconf-server-dispatcher-impl'";
+
+            leaf connection-timeout-millis {
+                description "Specifies timeout in milliseconds after which connection must be established.";
+                type uint32;
+                default 20000;
+            }
+
+            container boss-thread-group {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity netty:netty-threadgroup;
+                    }
+                }
+            }
+
+            container worker-thread-group {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity netty:netty-threadgroup;
+                    }
+                }
+            }
+
+            list mappers {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity nnm:netconf-northbound-mapper;
+                    }
+                }
+            }
+
+            container timer {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity netty:netty-timer;
+                    }
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file
index 3b83daa693fb926a7e28831fcf64f6761d3cdd7d..8e8a73b914cdf79ca7ad7e24d98ab31a859b0f44 100644 (file)
@@ -155,8 +155,8 @@ public class ConcurrentClientsTest {
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
-        NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory);
-        final NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
+        NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(serverNegotiatorFactory);
+        final NetconfServerDispatcherImpl dispatch = new NetconfServerDispatcherImpl(serverChannelInitializer, nettyGroup, nettyGroup);
 
         ChannelFuture s = dispatch.createServer(netconfAddress);
         s.await();
index ecc33ca90fd05f5392d6173c6d88cd4a7a36128c..df4069ac17f1a37bb81833c067bc9d46488825bc 100644 (file)
@@ -22,7 +22,7 @@ import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFact
 public class NetconfDispatcherImplTest {
 
     private EventLoopGroup nettyGroup;
-    private NetconfServerDispatcher dispatch;
+    private NetconfServerDispatcherImpl dispatch;
     private DefaultCommitNotificationProducer commitNot;
     private HashedWheelTimer hashedWheelTimer;
 
@@ -40,9 +40,9 @@ public class NetconfDispatcherImplTest {
         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
                 hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, ConcurrentClientsTest.createMockedMonitoringService());
 
-        NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory);
+        NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(serverNegotiatorFactory);
 
-        dispatch = new NetconfServerDispatcher(
+        dispatch = new NetconfServerDispatcherImpl(
                 serverChannelInitializer, nettyGroup, nettyGroup);
     }
 
index d744504bb2aa4160dfb6b57229a29e2623cad864..8cb569eaa283a974726ce3fab657f663fc72abb5 100644 (file)
@@ -20,6 +20,7 @@ import org.junit.Before;
 import org.junit.Test;
 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.osgi.framework.BundleContext;
 import org.osgi.framework.Filter;
@@ -46,6 +47,7 @@ public class NetconfOperationServiceFactoryTrackerTest {
         doNothing().when(listener).onRemoveNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class));
         doReturn(filter).when(context).createFilter(anyString());
         doReturn("").when(reference).toString();
+        doReturn(NetconfConstants.CONFIG_NETCONF_CONNECTOR).when(reference).getProperty(NetconfConstants.SERVICE_NAME);
         doReturn(factory).when(context).getService(any(ServiceReference.class));
         doReturn("").when(factory).toString();
         doNothing().when(listener).onAddNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class));
index bf1385398bd48d39b0c50a8dfc9ff5cd9501f4d1..b70e97bac9289f15a3793473fb43cc026b6ce121 100644 (file)
@@ -54,7 +54,7 @@ import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguratio
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
+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;
@@ -138,7 +138,7 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
     }
 
     private Channel startNetconfTcpServer(final NetconfOperationServiceFactoryListenerImpl factoriesListener) throws Exception {
-        final NetconfServerDispatcher dispatch = createDispatcher(factoriesListener, getNetconfMonitoringService(), getNotificationProducer());
+        final NetconfServerDispatcherImpl dispatch = createDispatcher(factoriesListener, getNetconfMonitoringService(), getNotificationProducer());
 
         final ChannelFuture s;
         if(getTcpServerAddress() instanceof LocalAddress) {
@@ -205,7 +205,7 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
         return yangDependencies;
     }
 
-    protected NetconfServerDispatcher createDispatcher(
+    protected NetconfServerDispatcherImpl createDispatcher(
             final NetconfOperationServiceFactoryListenerImpl factoriesListener, final SessionMonitoringService sessionMonitoringService,
             final DefaultCommitNotificationProducer commitNotifier) {
         final SessionIdProvider idProvider = new SessionIdProvider();
@@ -213,9 +213,9 @@ public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
         final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
                 hashedWheelTimer, factoriesListener, idProvider, SERVER_CONNECTION_TIMEOUT_MILLIS, commitNotifier, sessionMonitoringService);
 
-        final NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
+        final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
                 serverNegotiatorFactory);
-        return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
+        return new NetconfServerDispatcherImpl(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
     }
 
     protected HashedWheelTimer getHashedWheelTimer() {
index f5ae0ec610c59ca3c35be9a06b66e70f77dae4eb..21e50cd2eaddfa416018d0e68a60821e3a124e80 100644 (file)
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <configuration>
-          <instructions>
-            <Export-Package>org.opendaylight.controller.netconf.mapping.api,</Export-Package>
-          </instructions>
-        </configuration>
       </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/netconf-mapping-api/src/main/yang/netconf-northbound-mapper.yang b/opendaylight/netconf/netconf-mapping-api/src/main/yang/netconf-northbound-mapper.yang
new file mode 100644 (file)
index 0000000..a709665
--- /dev/null
@@ -0,0 +1,22 @@
+module netconf-northbound-mapper {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper";
+    prefix "nnm";
+
+    import config { prefix config; revision-date 2013-04-05; }
+
+    description
+        "This module contains the base YANG definitions for
+         mapping services plugged into a netconf northbound server";
+
+    revision "2015-01-14" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-northbound-mapper {
+        base "config:service-type";
+        config:java-class "org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory";
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-mdsal-config/pom.xml b/opendaylight/netconf/netconf-mdsal-config/pom.xml
new file mode 100644 (file)
index 0000000..f3c9313
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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
+  -->
+<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>netconf-mdsal-config</artifactId>
+  <description>Configuration files for netconf for mdsal</description>
+  <packaging>jar</packaging>
+  <build>
+    <plugins>
+        <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <phase>package</phase>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/initial/08-netconf-mdsal.xml</file>
+                  <type>xml</type>
+                  <classifier>config</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml b/opendaylight/netconf/netconf-mdsal-config/src/main/resources/initial/08-netconf-mdsal.xml
new file mode 100644 (file)
index 0000000..042447b
--- /dev/null
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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
+  -->
+
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+
+<snapshot>
+  <configuration>
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+          <module>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper">prefix:netconf-mdsal-mapper</type>
+              <name>netconf-mdsal-mapper</name>
+              <root-schema-service>
+                  <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+                  <name>yang-schema-service</name>
+              </root-schema-service>
+              <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper">
+                  <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>
+          </module>
+
+          <module>
+              <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">prefix:netconf-server-dispatcher-impl</type>
+              <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>
+              </mappers>
+              <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>
+              </boss-thread-group>
+              <worker-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-worker-group</name>
+              </worker-thread-group>
+              <timer 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-timer</type>
+                  <name>global-timer</name>
+              </timer>
+          </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>
+
+              <event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-event-executor</type>
+                  <name>global-event-executor</name>
+              </event-executor>
+              <worker-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
+                  <name>global-worker-group</name>
+              </worker-thread-group>
+              <processing-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">prefix:threadpool</type>
+                  <name>global-netconf-ssh-scheduled-executor</name>
+              </processing-executor>
+              <dispatcher xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+                  <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-dispatcher</type>
+                  <name>netconf-mdsal-server-dispatcher</name>
+              </dispatcher>
+
+              <username>admin</username>
+              <password>admin</password>
+          </module>
+
+      </modules>
+
+        <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+            <service>
+                <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-northbound-mapper</type>
+                <instance>
+                    <name>netconf-mdsal-mapper</name>
+                    <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:config:netconf:northbound">prefix:netconf-server-dispatcher</type>
+                <instance>
+                    <name>netconf-mdsal-server-dispatcher</name>
+                    <provider>/modules/module[type='netconf-server-dispatcher-impl'][name='netconf-mdsal-server-dispatcher']</provider>
+                </instance>
+            </service>
+        </services>
+
+    </data>
+  </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: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>
+  </required-capabilities>
+</snapshot>
index 0b4d1c2688d64307b51815b0d3b441f0ff9722ec..9e7c105aa4e0cf53f95ebeb290b181866e54cc8a 100644 (file)
@@ -8,8 +8,10 @@
 package org.opendaylight.controller.netconf.monitoring.osgi;
 
 import com.google.common.base.Preconditions;
+import java.util.Dictionary;
 import java.util.Hashtable;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.api.util.NetconfConstants;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -39,7 +41,9 @@ public class NetconfMonitoringServiceTracker extends ServiceTracker<NetconfMonit
         final NetconfOperationServiceFactory factory = new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
                 operationService);
 
-        reg = context.registerService(NetconfOperationServiceFactory.class, factory, new Hashtable<String, Object>());
+        Dictionary<String, String> properties = new Hashtable<>();
+        properties.put(NetconfConstants.SERVICE_NAME, NetconfConstants.NETCONF_MONITORING);
+        reg = context.registerService(NetconfOperationServiceFactory.class, factory, properties);
 
         return netconfMonitoringService;
     }
index ef950f8a788d768509749e3138afd3d3120e6a93..9eab5caff74fe3411d0ccaa847594d1834e574ea 100644 (file)
@@ -12,8 +12,10 @@ import com.google.common.base.Optional;
 import com.google.common.collect.Sets;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.Set;
+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;
@@ -66,7 +68,9 @@ public class Activator implements BundleActivator {
             }
         };
 
-        operationaServiceRegistration = context.registerService(NetconfOperationServiceFactory.class, netconfOperationServiceFactory, new Hashtable<String, Object>());
+        Dictionary<String, String> properties = new Hashtable<>();
+        properties.put(NetconfConstants.SERVICE_NAME, NetconfConstants.NETCONF_MONITORING);
+        operationaServiceRegistration = context.registerService(NetconfOperationServiceFactory.class, netconfOperationServiceFactory, properties);
 
     }
 
index 2371ede5770961aa2ae7064121c7b5a6945c9acd..03f7a2fac2fe05108825324ef059a26033d10ff3 100644 (file)
       <groupId>${project.groupId}</groupId>
       <artifactId>netconf-util</artifactId>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netconf-impl</artifactId>
+    </dependency>
     <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
+    </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>threadpool-config-api</artifactId>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>netty-config-api</artifactId>
+          <version>0.3.0-SNAPSHOT</version>
+      </dependency>
+
+      <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
     </dependency>
     <dependency>
       <groupId>org.bouncycastle</groupId>
           </execution>
         </executions>
       </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>
 
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/config/yang/netconf/northbound/ssh/NetconfNorthboundSshModule.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/config/yang/netconf/northbound/ssh/NetconfNorthboundSshModule.java
new file mode 100644 (file)
index 0000000..f17bc3c
--- /dev/null
@@ -0,0 +1,122 @@
+package org.opendaylight.controller.config.yang.netconf.northbound.ssh;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.local.LocalAddress;
+import io.netty.util.concurrent.GenericFutureListener;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.Executors;
+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.NetconfServerDispatcher;
+import org.opendaylight.controller.netconf.ssh.SshProxyServer;
+import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetconfNorthboundSshModule extends org.opendaylight.controller.config.yang.netconf.northbound.ssh.AbstractNetconfNorthboundSshModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NetconfNorthboundSshModule.class);
+
+    public NetconfNorthboundSshModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NetconfNorthboundSshModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final org.opendaylight.controller.config.yang.netconf.northbound.ssh.NetconfNorthboundSshModule 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 NetconfServerDispatcher dispatch = getDispatcherDependency();
+
+        final LocalAddress localAddress = new LocalAddress(getPort().toString());
+        final ChannelFuture localServer = dispatch.createLocalServer(localAddress);
+
+        final SshProxyServer sshProxyServer = new SshProxyServer(Executors.newScheduledThreadPool(1), getWorkerThreadGroupDependency(), getEventExecutorDependency());
+
+        final InetSocketAddress bindingAddress = getInetAddress();
+        final SshProxyServerConfigurationBuilder sshProxyServerConfigurationBuilder = new SshProxyServerConfigurationBuilder();
+        sshProxyServerConfigurationBuilder.setBindingAddress(bindingAddress);
+        sshProxyServerConfigurationBuilder.setLocalAddress(localAddress);
+        sshProxyServerConfigurationBuilder.setAuthenticator(new UserAuthenticator(getUsername(), getPassword()));
+        sshProxyServerConfigurationBuilder.setIdleTimeout(Integer.MAX_VALUE);
+        sshProxyServerConfigurationBuilder.setKeyPairProvider(new PEMGeneratorHostKeyProvider());
+
+        localServer.addListener(new GenericFutureListener<ChannelFuture>() {
+
+            @Override
+            public void operationComplete(final ChannelFuture future) {
+                if(future.isDone() && !future.isCancelled()) {
+                    try {
+                        sshProxyServer.bind(sshProxyServerConfigurationBuilder.createSshProxyServerConfiguration());
+                        LOG.info("Netconf SSH endpoint started successfully at {}", bindingAddress);
+                    } catch (final IOException e) {
+                        throw new RuntimeException("Unable to start SSH netconf server", e);
+                    }
+                } else {
+                    LOG.warn("Unable to start SSH netconf server at {}", bindingAddress, future.cause());
+                    throw new RuntimeException("Unable to start SSH netconf server", future.cause());
+                }
+            }
+        });
+
+        return new NetconfServerCloseable(localServer, sshProxyServer);
+    }
+
+    private InetSocketAddress getInetAddress() {
+        try {
+            final InetAddress inetAd = InetAddress.getByName(getBindingAddress().getIpv4Address() == null ? getBindingAddress().getIpv6Address().getValue() : getBindingAddress().getIpv4Address().getValue());
+            return new InetSocketAddress(inetAd, getPort().getValue());
+        } catch (final UnknownHostException e) {
+            throw new IllegalArgumentException("Unable to bind netconf endpoint to address " + getBindingAddress(), e);
+        }
+    }
+
+    private static final class NetconfServerCloseable implements AutoCloseable {
+        private final ChannelFuture localServer;
+        private final SshProxyServer sshProxyServer;
+
+        public NetconfServerCloseable(final ChannelFuture localServer, final SshProxyServer sshProxyServer) {
+            this.localServer = localServer;
+            this.sshProxyServer = sshProxyServer;
+        }
+
+        @Override
+        public void close() throws Exception {
+            sshProxyServer.close();
+
+            if(localServer.isDone()) {
+                localServer.channel().close();
+            } else {
+                localServer.cancel(true);
+            }
+        }
+    }
+
+
+    private static final class UserAuthenticator implements PasswordAuthenticator {
+
+        private final String username;
+        private final String password;
+
+        public UserAuthenticator(final String username, final String password) {
+            this.username = username;
+            this.password = password;
+        }
+
+        @Override
+        public boolean authenticate(final String username, final String password, final ServerSession session) {
+            // FIXME use aaa stuff here instead
+            return this.username.equals(username) && this.password.equals(password);
+        }
+    }
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/config/yang/netconf/northbound/ssh/NetconfNorthboundSshModuleFactory.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/config/yang/netconf/northbound/ssh/NetconfNorthboundSshModuleFactory.java
new file mode 100644 (file)
index 0000000..4e107ec
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-northbound-ssh yang module local name: netconf-northbound-ssh
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Mon Feb 09 14:09:07 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.netconf.northbound.ssh;
+public class NetconfNorthboundSshModuleFactory extends org.opendaylight.controller.config.yang.netconf.northbound.ssh.AbstractNetconfNorthboundSshModuleFactory {
+
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/yang/netconf-northbound-ssh.yang b/opendaylight/netconf/netconf-ssh/src/main/yang/netconf-northbound-ssh.yang
new file mode 100644 (file)
index 0000000..2e9d0b1
--- /dev/null
@@ -0,0 +1,94 @@
+module netconf-northbound-ssh {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh";
+    prefix "nni";
+
+    import netconf-northbound-mapper { prefix nnm; revision-date 2015-01-14; }
+    import netconf-northbound { prefix nn; revision-date 2015-01-14; }
+    import config { prefix config; revision-date 2013-04-05; }
+    import threadpool {prefix th;}
+    import netty {prefix netty;}
+    import ietf-inet-types { prefix inet; revision-date 2010-09-24; }
+
+    organization "Cisco Systems, Inc.";
+
+    description
+        "This module contains the base YANG definitions for
+         a default implementation of netconf northbound server";
+
+    revision "2015-01-14" {
+        description
+            "Initial revision.";
+    }
+
+    identity netconf-northbound-ssh {
+        base config:module-type;
+        config:java-name-prefix NetconfNorthboundSsh;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netconf-northbound-ssh {
+            when "/config:modules/config:module/config:type = 'netconf-northbound-ssh'";
+
+            leaf port {
+                type inet:port-number;
+                default 2830;
+            }
+
+            leaf binding-address {
+                type inet:ip-address;
+                default "0.0.0.0";
+            }
+
+            container processing-executor {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity th:scheduled-threadpool;
+                    }
+                }
+
+                description "Required by the mina-ssh library used in SSH endpoint";
+            }
+
+            container event-executor {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity netty:netty-event-executor;
+                    }
+                }
+            }
+
+            container worker-thread-group {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity netty:netty-threadgroup;
+                    }
+                }
+            }
+
+            container dispatcher {
+                uses config:service-ref {
+                    refine type {
+                        config:required-identity nn:netconf-server-dispatcher;
+                    }
+                }
+            }
+
+            // FIXME use auth provider from aaa instead
+            leaf username {
+                description "Specifies username credential";
+                type string;
+            }
+
+            leaf password {
+                description "Specifies password credential";
+                type string;
+            }
+
+
+        }
+    }
+
+}
\ No newline at end of file
index 8f24a5741ea8a52b68b31513721b2347b896b273..30b307658964c59706818fff40846a135387cb28 100644 (file)
@@ -58,7 +58,7 @@ import org.apache.sshd.server.session.ServerSession;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
+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;
@@ -125,7 +125,7 @@ public class NetconfDeviceSimulator implements Closeable {
         this.nioExecutor = nioExecutor;
     }
 
-    private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi, final int generateConfigsTimeout, final Optional<File> notificationsFile) {
+    private NetconfServerDispatcherImpl createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi, final int generateConfigsTimeout, final Optional<File> notificationsFile) {
 
         final Set<Capability> capabilities = Sets.newHashSet(Collections2.transform(moduleBuilders.keySet(), new Function<ModuleBuilder, Capability>() {
             @Override
@@ -154,9 +154,9 @@ public class NetconfDeviceSimulator implements Closeable {
         final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
                 hashedWheelTimer, simulatedOperationProvider, idProvider, generateConfigsTimeout, commitNotifier, new LoggingMonitoringService(), serverCapabilities);
 
-        final NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
+        final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
                 serverNegotiatorFactory);
-        return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
+        return new NetconfServerDispatcherImpl(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
     }
 
     private Map<ModuleBuilder, String> toModuleBuilders(final Map<SourceIdentifier, Map.Entry<ASTSchemaSource, YangTextSchemaSource>> sources) {
@@ -192,7 +192,7 @@ public class NetconfDeviceSimulator implements Closeable {
 
         final Map<ModuleBuilder, String> moduleBuilders = parseSchemasToModuleBuilders(params);
 
-        final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout, Optional.fromNullable(params.notificationFile));
+        final NetconfServerDispatcherImpl dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout, Optional.fromNullable(params.notificationFile));
 
         int currentPort = params.startingPort;
 
index 653dd70b2986bde1bcb91f058899e949478c31dd..4566845e4f88fe7b3c1ee23e12b6ef41a5e6a653 100644 (file)
@@ -20,6 +20,7 @@
     <module>netconf-config</module>
     <module>netconf-impl</module>
     <module>config-netconf-connector</module>
+    <module>mdsal-netconf-connector</module>
     <module>netconf-util</module>
     <module>netconf-netty-util</module>
     <module>config-persister-impl</module>
@@ -33,6 +34,7 @@
     <module>ietf-netconf-notifications</module>
     <module>ietf-netconf-monitoring-extension</module>
     <module>netconf-connector-config</module>
+    <module>netconf-mdsal-config</module>
     <module>netconf-auth</module>
     <module>netconf-usermanager</module>
     <module>netconf-testtool</module>