Merge "BUG 1595 - Clustering : NPE on startup"
authorEd Warnicke <eaw@cisco.com>
Thu, 4 Sep 2014 22:53:39 +0000 (22:53 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 4 Sep 2014 22:53:39 +0000 (22:53 +0000)
203 files changed:
features/akka/pom.xml [new file with mode: 0644]
features/akka/src/main/resources/features.xml [new file with mode: 0644]
features/base/pom.xml
features/base/src/main/resources/features.xml
features/mdsal/pom.xml
features/mdsal/src/main/resources/features.xml
features/netconf/pom.xml
features/netconf/src/main/resources/features.xml
features/pom.xml
opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/pom.xml
opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/src/main/resources/80-__repoName__.xml [moved from opendaylight/archetypes/opendaylight-configfile-archetype/src/main/resources/archetype-resources/src/main/resources/80-configfile.xml with 100% similarity]
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/RefreshingSCPModuleInfoRegistryTest.java [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf-resources/src/main/resources/etc/custom.properties
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/distribution/opendaylight/src/main/resources/run.sh
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-akka-raft/pom.xml
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleActor.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/ExampleConfigParamsImpl.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/example/TestDriver.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/AbstractReplicatedLogImpl.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/ConfigParams.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/DefaultConfigParamsImpl.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/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/SerializationUtils.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/Snapshot.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/ApplySnapshot.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/CaptureSnapshot.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/CaptureSnapshotReply.java [new file with mode: 0644]
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/Follower.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/messages/InstallSnapshot.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/messages/InstallSnapshotReply.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/protobuff/messages/InstallSnapshotMessages.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/main/resources/InstallSnapshot.proto [new file with mode: 0644]
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/behaviors/FollowerTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DomToBindingRpcForwarder.java
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-clustering-commons/pom.xml
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/common/actor/MeteredBoundedMailbox.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlUtils.java
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/common/actor/MeteredBoundedMailboxTest.java
opendaylight/md-sal/sal-clustering-config/pom.xml
opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/akka.conf
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/AbstractMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBeanImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerStats.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStats.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/pom.xml
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ActorSystemFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java [moved from opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardContext.java with 87% similarity]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreProperties.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardReadWriteTransaction.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/ShardTransactionChain.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardWriteTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohort.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/AbstractBaseMBean.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardMBeanFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStats.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStatsMBean.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedConfigDataStoreProviderModule.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedConfigDataStoreProviderModuleFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedOperationalDataStoreProviderModule.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedOperationalDataStoreProviderModuleFactory.java
opendaylight/md-sal/sal-distributed-datastore/src/main/resources/application.conf
opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardManagerTest.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/ShardTransactionChainTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionFailureTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTransactionTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortFailureTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/jmx/mbeans/shard/ShardStatsTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/TestUtils.java
opendaylight/md-sal/sal-distributed-datastore/src/test/resources/application.conf
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomInmemoryDataBrokerModule.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/TranslatingListenerInvoker.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBean.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/GlobalBundleScanningSchemaServiceImpl.java
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImplTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/statistics/DOMStoreStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryConfigDataStoreProviderModule.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChangeListenerNotifyTask.java [deleted file]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStoreConfigProperties.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStoreFactory.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/jmx/InMemoryDataStoreStats.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfStateSchemas.java
opendaylight/md-sal/sal-remoterpc-connector/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/ActorSystemFactory.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementation.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderFactory.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcBroker.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcErrorsException.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/ErrorResponse.java [deleted file]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/ActorUtil.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/AkkaConfigurationReader.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/DefaultAkkaConfigurationReader.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/resources/application.conf
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/AbstractRpcTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/ActorSystemFactoryTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementationTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RemoteRpcProviderTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RouteRpcListenerTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcBrokerTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcListenerTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/utils/LatestEntryRoutingLogicTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf
opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/test-rpc.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/pom.xml
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/rest/connector/RestConnectorModule.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfConstants.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/AbstractIdentifierAwareJaxRsProvider.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeJsonBodyWriter.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfApplication.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlNormalizedNodeBodyReader.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToCompositeNodeReader.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java [deleted file]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdentifierContext.java [moved from opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/InstanceIdWithSchemaNode.java with 71% similarity]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NormalizedDataPrunner.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NormalizedNodeContext.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfProviderImpl.java [moved from opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProviderImpl.java with 59% similarity]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StatisticsRestconfServiceWrapper.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java
opendaylight/md-sal/sal-rest-connector/src/main/yang/opendaylight-rest-connector.yang
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java
opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml
opendaylight/md-sal/sal-rest-docgen/src/main/resources/explorer/index.html
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java
opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/AbstractNetconfConfigTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/HardcodedYangStoreService.java [deleted file]
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITMonitoringTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java [deleted file]
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/SSLUtil.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/AcceptingAuthProvider.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronRouter_Interface.java
opendaylight/samples/northbound/loadbalancer/pom.xml

diff --git a/features/akka/pom.xml b/features/akka/pom.xml
new file mode 100644 (file)
index 0000000..f1f3017
--- /dev/null
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Necessary TODO: Put your copyright here.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+   <modelVersion>4.0.0</modelVersion>
+   <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.2-SNAPSHOT</version>
+    <relativePath>../../opendaylight/commons/opendaylight</relativePath>
+   </parent>
+   <artifactId>features-akka</artifactId>
+   <groupId>org.opendaylight.controller</groupId>
+   <packaging>jar</packaging>
+   <properties>
+      <features.file>features.xml</features.file>
+      <!-- Optional TODO: Move these properties to your parent pom and possibly
+            DependencyManagement section of your parent pom -->
+      <branding.version>1.0.0-SNAPSHOT</branding.version>
+      <karaf.resources.version>1.4.2-SNAPSHOT</karaf.resources.version>
+      <karaf.version>3.0.1</karaf.version>
+      <feature.test.version>0.6.2-SNAPSHOT</feature.test.version>
+      <karaf.empty.version>1.4.2-SNAPSHOT</karaf.empty.version>
+      <surefire.version>2.16</surefire.version>
+   </properties>
+   <dependencies>
+    <!--
+      Necessary TODO: Put dependencies on any feature repos
+      you use in your features.xml file.
+
+      Note: they will need to be <type>xml</xml>
+      and <classifier>features</classifier>.
+      One other thing to watch for is to make sure they are
+      <scope>compile</compile>, which they should be by default,
+      but be cautious lest they be at a different scope in a parent pom.
+
+      Examples:
+        <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>features-yangtools</artifactId>
+          <version>0.6.2-SNAPSHOT</version>
+          <classifier>features</classifier>
+          <type>xml</type>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>features-mdsal</artifactId>
+          <version>1.1-SNAPSHOT</version>
+          <classifier>features</classifier>
+          <type>xml</type>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.openflowplugin</groupId>
+          <artifactId>features-openflowplugin</artifactId>
+          <version>0.0.3-SNAPSHOT</version>
+          <classifier>features</classifier>
+          <type>xml</type>
+        </dependency>
+    -->
+
+    <!--
+      Necessary TODO: Put dependencies for bundles directly referenced
+      in your features.xml file.  For every <bundle> reference in your
+      features.xml file, you need a corresponding dependency here.
+
+      Examples:
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>controller-provider</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>controller-model</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+    -->
+
+    <!--
+      Necessary TODO: Put dependencies for configfiles directly referenced
+      in your features.xml file.  For every <configfile> reference in your
+      features.xml file, you need a corresponding dependency here.
+
+      Example (presuming here version is coming from the parent pom):
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>controller-config</artifactId>
+        <version>${project.version}</version>
+        <type>xml</type>
+        <classifier>config</classifier>
+      </dependency>
+    -->
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-library</artifactId>
+      <version>${scala.version}.${scala.micro.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-reflect</artifactId>
+      <version>${scala.version}.${scala.micro.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe</groupId>
+      <artifactId>config</artifactId>
+      <version>${typesafe.config.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-actor_${scala.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-slf4j_${scala.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-osgi_${scala.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.uncommons.maths</groupId>
+        <artifactId>uncommons-maths</artifactId>
+        <version>${uncommons.maths.version}</version>
+        <exclusions>
+            <exclusion>
+                <groupId>jfree</groupId>
+                <artifactId>jcommon</artifactId>
+            </exclusion>
+            <exclusion>
+                <groupId>jfree</groupId>
+                <artifactId>jfreechart</artifactId>
+            </exclusion>
+        </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>com.google.protobuf</groupId>
+      <artifactId>protobuf-java</artifactId>
+      <version>${protobuf.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty</artifactId>
+      <version>3.8.0.Final</version>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-remote_${scala.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-cluster_${scala.version}</artifactId>
+      <version>${akka.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.iq80.leveldb</groupId>
+      <artifactId>leveldb</artifactId>
+      <version>${leveldb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.fusesource.leveldbjni</groupId>
+      <artifactId>leveldbjni-all</artifactId>
+      <version>${leveldbjni.version}</version>
+    </dependency>
+    <!--
+      Optional TODO: Remove TODO comments.
+    -->
+    <!-- test to validate features.xml -->
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-test</artifactId>
+      <version>${feature.test.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- dependency for opendaylight-karaf-empty for use by testing -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>opendaylight-karaf-empty</artifactId>
+      <version>${karaf.empty.version}</version>
+      <type>zip</type>
+    </dependency>
+    <!-- Uncomment this if you get an error : java.lang.NoSuchMethodError: org.slf4j.helpers.MessageFormatter.format(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Lorg/slf4j/helpers/FormattingTuple;
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>1.7.2</version>
+    </dependency>
+    -->
+
+   </dependencies>
+   <build>
+      <resources>
+         <resource>
+            <directory>src/main/resources</directory>
+            <filtering>true</filtering>
+         </resource>
+      </resources>
+      <plugins>
+         <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-resources-plugin</artifactId>
+            <executions>
+               <execution>
+                  <id>filter</id>
+                  <phase>generate-resources</phase>
+                  <goals>
+                     <goal>resources</goal>
+                  </goals>
+               </execution>
+            </executions>
+         </plugin>
+         <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>build-helper-maven-plugin</artifactId>
+            <executions>
+               <execution>
+                  <id>attach-artifacts</id>
+                  <phase>package</phase>
+                  <goals>
+                     <goal>attach-artifact</goal>
+                  </goals>
+                  <configuration>
+                     <artifacts>
+                        <artifact>
+                           <file>${project.build.directory}/classes/${features.file}</file>
+                           <type>xml</type>
+                           <classifier>features</classifier>
+                        </artifact>
+                     </artifacts>
+                  </configuration>
+               </execution>
+            </executions>
+         </plugin>
+         <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <version>${surefire.version}</version>
+            <configuration>
+              <systemPropertyVariables>
+                <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>
+                <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>
+                <karaf.distro.version>${karaf.empty.version}</karaf.distro.version>
+              </systemPropertyVariables>
+              <dependenciesToScan>
+               <dependency>org.opendaylight.yangtools:features-test</dependency>
+              </dependenciesToScan>
+            </configuration>
+          </plugin>
+      </plugins>
+   </build>
+   <scm>
+      <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+      <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+      <tag>HEAD</tag>
+      <url>https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=summary</url>
+   </scm>
+</project>
diff --git a/features/akka/src/main/resources/features.xml b/features/akka/src/main/resources/features.xml
new file mode 100644 (file)
index 0000000..182ff76
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Necessary TODO: Put your copyright statement here
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<features name="odl-controller-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+    <!--
+        Necessary TODO: Please read the features guidelines:
+        https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Feature_Best_Practices
+    -->
+    <!--
+    Necessary TODO: Add repo entries for the repositories of features you refer to
+        in this feature file but do not define here.
+        Examples:
+            <repository>mvn:org.opendaylight.yangtools/features-yangtools/0.6.2-SNAPSHOT/xml/features</repository>
+            <repository>mvn:org.opendaylight.controller/features-mdsal/1.1-SNAPSHOT/xml/features</repository>
+            <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/0.0.3-SNAPSHOT/xml/features</repository>
+    -->
+    <feature name='odl-akka-all' version='${project.version}' description='OpenDaylight :: Akka :: All'>
+        <!--
+            Necessary TODO:
+            List all of the user consumable features you define in this feature file here.
+            Generally you would *not* list individual bundles here, but only features defined in *this* file.
+            It is useful to list them in the same order they occur in the file.
+
+            Examples:
+            <feature version='${project.version}'>odl-controller-provider</feature>
+            <feature version='${project.version}'>odl-controller-model</feature>
+        -->
+        <feature version="${scala.version}">odl-akka-scala</feature>
+        <feature version="${akka.version}">odl-akka-system</feature>
+        <feature version="${akka.version}">odl-akka-clustering</feature>
+        <feature version='0.7'>odl-akka-leveldb</feature>
+        <feature version="${akka.version}">odl-akka-persistence</feature>
+    </feature>
+    <!--
+        Necessary TODO: Define your features.  It is useful to list then in order of dependency.  So if A depends on B, list A first.
+        When naming your features please be mindful of the guidelines:
+            https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines
+        Particularly:
+            a) Prefixing names with 'odl-': https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Feature_Naming
+            b) Descriptions: https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Description
+            c) Avoid start-levels: https://wiki.opendaylight.org/view/Runtime:Karaf_Features_Guidelines#Avoid_start-levels
+
+        It's also nice to list inside a feature, first the features it needs, then the bundles it needs, then the configfiles.
+        Examples:
+
+        * Basic MD-SAL Provider
+        <feature name='odl-controller-provider' version='${project.version}' description='OpenDaylight :: controller :: Provider '>
+            <feature version='1.1-SNAPSHOT'>odl-mdsal-broker</feature>
+            <feature version='${project.version}'>odl-controller-model</feature>
+            <bundle>mvn:org.opendaylight.controller/controller-provider/${project.version}</bundle>
+            ... whatever other bundles you need
+        </feature>
+
+        * Basic MD-SAL Model feature
+        <feature name='odl-controller-model' version='${project.version}' description='OpenDaylight :: controller :: Model'>
+            <feature version='0.6.2-SNAPSHOT'>odl-yangtools-binding</feature>
+            <feature version='0.6.2-SNAPSHOT'>odl-yangtools-models</feature>
+            <bundle>mvn:org.opendaylight.controller/controller-model/${project.version}</bundle>
+            ... whatever other bundles you need
+        </feature>
+
+        * Config Subsystem example - the config file is your config subsystem configuration
+        <feature name='odl-controller-provider' version='${project.version}' description='OpenDaylight :: controller :: Provider'>
+            <feature version='1.1-SNAPSHOT'>odl-mdsal-broker</feature>
+            <bundle>mvn:org.opendaylight.controller/controller-provider/${project.version}</bundle>
+            <configfile finalname="etc/opendaylight/karaf/80-controller.xml">mvn:org.opendaylight.controller/controller-config/${project.version}/xml/config</configfile>
+            ... whatever other bundles you need
+        </feature>
+
+        * Basic MD-SAL Provider that uses openflowplugin-flow-services (which brings along odl-mdsal-broker)
+        <feature name='odl-controller-provider' version='${project.version}' description='OpenDaylight :: controller :: Provider'>
+            <feature version='0.0.3-SNAPSHOT'>odl-openflowplugin-flow-services</feature>
+            <bundle>mvn:org.opendaylight.controller/controller-provider/${project.version}</bundle>
+            ... whatever other bundles you need
+        </feature>
+
+    -->
+    <feature name="odl-akka-scala" description="Scala Runtime for OpenDaylight" version="${scala.version}">
+        <bundle>mvn:org.scala-lang/scala-library/${scala.version}.${scala.micro.version}</bundle>
+        <bundle>mvn:org.scala-lang/scala-reflect/${scala.version}.${scala.micro.version}</bundle>
+    </feature>
+    <feature name="odl-akka-system" description="Akka Actor Framework System Bundles" version="${akka.version}">
+        <feature version="${scala.version}">odl-akka-scala</feature>
+        <bundle>mvn:com.typesafe/config/${typesafe.config.version}</bundle>
+        <bundle>mvn:com.typesafe.akka/akka-actor_${scala.version}/${akka.version}</bundle>
+        <bundle>mvn:com.typesafe.akka/akka-slf4j_${scala.version}/${akka.version}</bundle>
+        <bundle>mvn:com.typesafe.akka/akka-osgi_${scala.version}/${akka.version}</bundle>
+    </feature>
+    <feature name="odl-akka-clustering" description="Akka Clustering" version="${akka.version}">
+        <feature version="${akka.version}">odl-akka-system</feature>
+        <bundle>wrap:mvn:org.uncommons.maths/uncommons-maths/${uncommons.maths.version}</bundle>
+        <bundle>mvn:com.google.protobuf/protobuf-java/${protobuf.version}</bundle>
+        <bundle>mvn:io.netty/netty/3.8.0.Final</bundle>
+        <bundle>mvn:com.typesafe.akka/akka-remote_${scala.version}/${akka.version}</bundle>
+        <bundle>mvn:com.typesafe.akka/akka-cluster_${scala.version}/${akka.version}</bundle>
+    </feature>
+    <feature name='odl-akka-leveldb' description='LevelDB' version='0.7'>
+        <bundle>wrap:mvn:org.iq80.leveldb/leveldb/${leveldb.version}</bundle>
+        <bundle>mvn:org.fusesource.leveldbjni/leveldbjni-all/${leveldbjni.version}</bundle>
+    </feature>
+    <feature name='odl-akka-persistence' description='Akka Persistence' version="${akka.version}">
+        <feature version='0.7'>odl-akka-leveldb</feature>
+        <feature version="${akka.version}">odl-akka-system</feature>
+        <bundle>mvn:com.typesafe.akka/akka-persistence-experimental_${scala.version}/${akka.version}</bundle>
+        <bundle>wrap:mvn:com.google.protobuf/protobuf-java/${protobuf.version}$overwrite=merge&amp;DynamicImport-Package=org.opendaylight.controller.protobuff.messages.*;org.opendaylight.controller.cluster.raft.protobuff.client.messages.*</bundle>
+    </feature>
+    <!-- Optional TODO: Remove TODO Comments -->
+
+</features>
index ed8e2a8c20d2765ade8cbe42856f8b94460eeb40..8fec90fd9dc3ddc9ef3c3e80ecb040b617c44515 100644 (file)
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.catalina</artifactId>
-      <version>7.0.53.v201406061610</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.catalina.ha</artifactId>
-      <version>7.0.53.v201406070630</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.catalina.tribes</artifactId>
-      <version>7.0.53.v201406070630</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.coyote</artifactId>
-      <version>7.0.53.v201406070630</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.el</artifactId>
-      <version>7.0.53.v201406060720</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.jasper</artifactId>
-      <version>7.0.53.v201406070630</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.juli.extras</artifactId>
-      <version>7.0.53.v201406060720</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.tomcat.api</artifactId>
-      <version>7.0.53.v201406060720</version>
     </dependency>
     <dependency>
       <groupId>orbit</groupId>
       <artifactId>org.apache.tomcat.util</artifactId>
-      <version>7.0.53.v201406070630</version>
     </dependency>
     <dependency>
       <groupId>org.aopalliance</groupId>
index 999cf704d2bedf212a283864e6d8e4d74f10fd68..e4c455ccca6a7078fb0f319274b4af07b02a3853 100644 (file)
    <feature name="odl-base-tomcat" description="OpenDaylight Tomcat" version="7.0.53">
       <feature>odl-base-gemini-web</feature>
       <feature>odl-base-eclipselink-persistence</feature>
-      <bundle start="true">mvn:orbit/org.apache.catalina/${commons.karaf.catalina}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.catalina/${commons.catalina}</bundle>
       <bundle start="true">mvn:geminiweb/org.eclipse.gemini.web.tomcat/${geminiweb.version}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.catalina.ha/${commons.karaf.catalina.ha}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.catalina.tribes/${commons.karaf.catalina.tribes}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.coyote/${commons.karaf.coyote}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.el/${commons.karaf.el}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.jasper/${commons.karaf.jasper}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.juli.extras/${commons.karaf.juli.version}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.tomcat.api/${commons.karaf.tomcat.api}</bundle>
-      <bundle start="true">mvn:orbit/org.apache.tomcat.util/${commons.karaf.tomcat.util}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.catalina.ha/${commons.catalina.ha}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.catalina.tribes/${commons.catalina.tribes}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.coyote/${commons.coyote}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.el/${commons.el}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.jasper/${commons.jasper}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.juli.extras/${commons.juli.version}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.tomcat.api/${commons.tomcat.api}</bundle>
+      <bundle start="true">mvn:orbit/org.apache.tomcat.util/${commons.tomcat.util}</bundle>
       <bundle start="true" >mvn:org.opendaylight.controller/karaf-tomcat-security/${karaf.security.version}</bundle>
       <bundle start="true">wrap:mvn:virgomirror/org.eclipse.jdt.core.compiler.batch/${eclipse.jdt.core.compiler.batch.version}</bundle>
    </feature>
index 3a9de7abcd13cc74c80833a6152bd84a43e87003..38fe92fa8280a03d6f01e1a24035c067a24598fa 100644 (file)
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-akka</artifactId>
+      <version>${commons.opendaylight.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-core-api</artifactId>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-dom-xsql</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-dom-xsql-config</artifactId>
+      <classifier>config</classifier>
+      <type>xml</type>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-binding-api</artifactId>
       <type>xml</type>
       <classifier>config</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-distributed-datastore</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-remoterpc-connector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-clustering-commons</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-akka-raft</artifactId>
+      <version>${mdsal.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-clustering-config</artifactId>
+      <version>${mdsal.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-netconf-connector</artifactId>
       <type>xml</type>
       <classifier>config</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-rest-docgen</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-annotations</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.datatype</groupId>
+      <artifactId>jackson-datatype-json-org</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.module</groupId>
+      <artifactId>jackson-module-jaxb-annotations</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.jaxrs</groupId>
+      <artifactId>jackson-jaxrs-base</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.jaxrs</groupId>
+      <artifactId>jackson-jaxrs-json-provider</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.json</groupId>
+      <artifactId>json</artifactId>
+    </dependency>
     <!-- test to validate features.xml -->
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
index 9e29fc84f813ffb15e4c55440824c2708785b538..ae73c71ee4c9f46b362c48e98015b5e27f538497 100644 (file)
@@ -7,11 +7,13 @@
     <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-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>
         <feature version='${project.version}'>odl-mdsal-netconf-connector</feature>
         <feature version='${project.version}'>odl-restconf</feature>
         <feature version='${project.version}'>odl-mdsal-xsql</feature>
+        <feature version='${project.version}'>odl-mdsal-clustering</feature>
         <feature version='${project.version}'>odl-toaster</feature>
     </feature>
     <feature name='odl-mdsal-broker' version='${project.version}' description="OpenDaylight :: MDSAL :: Broker">
@@ -45,6 +47,7 @@
         <feature>war</feature>
         <bundle>mvn:org.opendaylight.controller/sal-rest-connector/${project.version}</bundle>
         <bundle>mvn:com.google.code.gson/gson/${gson.version}</bundle>
+        <bundle>mvn:org.opendaylight.yangtools/yang-data-codec-gson/${yangtools.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
         <bundle>mvn:com.sun.jersey/jersey-servlet/${jersey.version}</bundle>
         <bundle>mvn:org.opendaylight.controller/sal-dom-xsql/${project.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.xsql.configfile}">mvn:org.opendaylight.controller/sal-dom-xsql-config/${project.version}/xml/config</configfile>
     </feature>
+    <feature name ='odl-mdsal-apidocs' version='${project.version}'>
+        <feature version='${project.version}'>odl-restconf</feature>
+        <bundle>mvn:org.opendaylight.controller/sal-rest-docgen/${project.version}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson.version}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-core/${jackson.version}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.core/jackson-databind/${jackson.version}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.datatype/jackson-datatype-json-org/${jackson.version}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.module/jackson-module-jaxb-annotations/${jackson.version}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/${jackson.version}</bundle>
+        <bundle>mvn:com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/${jackson.version}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-servlet/${jersey.version}</bundle>
+        <bundle>wrap:mvn:org.json/json/${org.json.version}</bundle>
+    </feature>
+    <feature name ='odl-mdsal-clustering-commons' version='${project.version}'>
+        <feature version='${project.version}'>odl-mdsal-broker</feature>
+        <feature version='${akka.version}'>odl-akka-system</feature>
+        <feature version='${akka.version}'>odl-akka-persistence</feature>
+        <bundle>mvn:org.opendaylight.controller/sal-clustering-commons/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller/sal-akka-raft/${project.version}</bundle>
+        <bundle>mvn:com.codahale.metrics/metrics-core/3.0.1</bundle>
+    </feature>
+    <feature name ='odl-mdsal-distributed-datastore' version='${project.version}'>
+        <feature version='${project.version}'>odl-mdsal-broker</feature>
+        <feature version='${project.version}'>odl-mdsal-clustering-commons</feature>
+        <feature version='${akka.version}'>odl-akka-clustering</feature>
+        <bundle>mvn:org.opendaylight.controller/sal-distributed-datastore/${project.version}</bundle>
+    </feature>
+    <feature name ='odl-mdsal-remoterpc-connector' version='${project.version}'>
+        <feature version='${project.version}'>odl-mdsal-broker</feature>
+        <feature version='${project.version}'>odl-mdsal-clustering-commons</feature>
+        <feature version='${akka.version}'>odl-akka-clustering</feature>
+        <feature version='0.7'>odl-akka-leveldb</feature>
+        <bundle>mvn:org.opendaylight.controller/sal-remoterpc-connector/${project.version}</bundle>
+    </feature>
+    <feature name ='odl-mdsal-clustering' version='${project.version}'>
+        <feature version='${project.version}'>odl-mdsal-remoterpc-connector</feature>
+        <feature version='${project.version}'>odl-mdsal-distributed-datastore</feature>
+        <configfile finalname="${config.configfile.directory}/${config.clustering.configfile}">mvn:org.opendaylight.controller/sal-clustering-config/${project.version}/xml/config</configfile>
+        <configfile finalname="configuration/initial/akka.conf">mvn:org.opendaylight.controller/sal-clustering-config/${project.version}/xml/akkaconf</configfile>
+        <configfile finalname="configuration/initial/module-shards.conf">mvn:org.opendaylight.controller/sal-clustering-config/${project.version}/xml/moduleshardconf</configfile>
+        <configfile finalname="configuration/initial/modules.conf">mvn:org.opendaylight.controller/sal-clustering-config/${project.version}/xml/moduleconf</configfile>
+    </feature>
 </features>
index 51d6f6291b08adb86157c75523bc93067401b906..d18d227f0013d1e861d56759840403dee0c06ada 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-auth</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>ietf-netconf-monitoring</artifactId>
index 1453a5fb969a9d1e3f6b9f6bec88cebb59182d3f..0a6356231a84d1c671fa07e48212200a61451490 100644 (file)
@@ -19,6 +19,7 @@
   <feature name='odl-netconf-api' version='${project.version}' description="OpenDaylight :: Netconf :: API">
     <feature version='${protocol-framework.version}'>odl-protocol-framework</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-api/${project.version}</bundle>
+    <bundle>mvn:org.opendaylight.controller/netconf-auth/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring-extension/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf-inet-types.version}</bundle>
index 039060b4aeb7bec891d74ccb5ea018ef19855bad..01156cf02a1af9343ff2a49c45feff037bb36e4a 100644 (file)
@@ -26,5 +26,6 @@
     <module>netconf</module>
     <module>protocol-framework</module>
     <module>adsal-compatibility</module>
+    <module>akka</module>
   </modules>
 </project>
\ No newline at end of file
index e217b9abfac46321e8922812ac4b2c4a1a7a6c39..3c778e262b66ec985a1b67b4ec78a4e542f71d03 100644 (file)
     will pick the pom.xml from the parent directory as the parent pom, which may or may
     not be correct.
   -->
+  <!--
+    Necessary TODO: Replace the contents of src/main/resources/80-${repoName}.xml with
+    the proper config subsystem contents for your module
+  -->
   <artifactId>${artifactId}</artifactId>
   <groupId>${groupId}</groupId>
   <description>Configuration files for md-sal</description>
@@ -23,7 +27,7 @@
   <packaging>jar</packaging>
   <properties>
       <!-- Optional TODO: Rename your configfile to taste -->
-      <configfile>80-configfile.xml</configfile>
+      <configfile>80-${repoName}.xml</configfile>
   </properties>
   <build>
     <plugins>
                   <type>xml</type>
                   <classifier>config</classifier>
                 </artifact>
+                <!--
+                  Optional TODO: Add additional config files
+                    You may need to add more than one config file
+                    if so, you just need to add additional <artifact> entries
+                    here WITH DIFFERENT CLASSIFIERS
+                    Example:
+                    <artifact>
+                      <file>${project.build.directory}/classes/<another-configfile></file>
+                      <type>xml</type>
+                      <classifier>config-<meaningful suffix to describe your other configfile></classifier>
+                    </artifact>
+                -->
               </artifacts>
             </configuration>
           </execution>
index 425e968cf7ee9255cde33a7440834ac0ae05a576..b05170ddc842e6011109dc3b4604cc32d53a5251 100644 (file)
     <clustering.test.version>0.4.2-SNAPSHOT</clustering.test.version>
     <commmons.northbound.version>0.4.2-SNAPSHOT</commmons.northbound.version>
     <!-- Third Party Versions -->
-    <commons.catalina>7.0.32.v201211201336</commons.catalina>
-    <commons.catalina.ha>7.0.32.v201211201952</commons.catalina.ha>
-    <commons.catalina.tribes>7.0.32.v201211201952</commons.catalina.tribes>
-    <commons.coyote>7.0.32.v201211201952</commons.coyote>
-    <commons.el>7.0.32.v201211081135</commons.el>
-    <commons.jasper>7.0.32.v201211201952</commons.jasper>
-    <commons.juli.version>7.0.32.v201211081135</commons.juli.version>
-    <commons.tomcat.api>7.0.32.v201211081135</commons.tomcat.api>
-    <commons.tomcat.util>7.0.32.v201211201952</commons.tomcat.util>
+    <codahale.metrics.version>3.0.1</codahale.metrics.version>
 
-    <commons.karaf.catalina>7.0.53.v201406061610</commons.karaf.catalina>
-    <commons.karaf.catalina.ha>7.0.53.v201406070630</commons.karaf.catalina.ha>
-    <commons.karaf.catalina.tribes>7.0.53.v201406070630</commons.karaf.catalina.tribes>
-    <commons.karaf.coyote>7.0.53.v201406070630</commons.karaf.coyote>
-    <commons.karaf.el>7.0.53.v201406060720</commons.karaf.el>
-    <commons.karaf.jasper>7.0.53.v201406070630</commons.karaf.jasper>
-    <commons.karaf.juli.version>7.0.53.v201406060720</commons.karaf.juli.version>
-    <commons.karaf.tomcat.api>7.0.53.v201406060720</commons.karaf.tomcat.api>
-    <commons.karaf.tomcat.util>7.0.53.v201406070630</commons.karaf.tomcat.util>
+    <commons.catalina>7.0.53.v201406061610</commons.catalina>
+    <commons.catalina.ha>7.0.53.v201406070630</commons.catalina.ha>
+    <commons.catalina.tribes>7.0.53.v201406070630</commons.catalina.tribes>
+    <commons.coyote>7.0.53.v201406070630</commons.coyote>
+    <commons.el>7.0.53.v201406060720</commons.el>
+    <commons.jasper>7.0.53.v201406070630</commons.jasper>
+    <commons.juli.version>7.0.53.v201406060720</commons.juli.version>
+    <commons.tomcat.api>7.0.53.v201406060720</commons.tomcat.api>
+    <commons.tomcat.util>7.0.53.v201406070630</commons.tomcat.util>
 
     <commons.checkstyle.version>0.0.3-SNAPSHOT</commons.checkstyle.version>
     <commons.fileupload.version>1.2.2</commons.fileupload.version>
@@ -76,6 +68,7 @@
     <concurrentlinkedhashmap.version>1.4</concurrentlinkedhashmap.version>
     <config.version>0.2.5-SNAPSHOT</config.version>
     <config.configfile.directory>etc/opendaylight/karaf</config.configfile.directory>
+    <config.clustering.configfile>05-clustering.xml</config.clustering.configfile>
     <config.netty.configfile>00-netty.xml</config.netty.configfile>
     <config.mdsal.configfile>01-mdsal.xml</config.mdsal.configfile>
     <config.xsql.configfile>04-xsql.xml</config.xsql.configfile>
     <topologymanager.shell.version>1.0.0-SNAPSHOT</topologymanager.shell.version>
     <troubleshoot.web.version>0.4.2-SNAPSHOT</troubleshoot.web.version>
     <typesafe.config.version>1.2.0</typesafe.config.version>
-    <uncommons.maths.version>1.2.2</uncommons.maths.version>
+    <uncommons.maths.version>1.2.2a</uncommons.maths.version>
     <usermanager.implementation.version>0.4.2-SNAPSHOT</usermanager.implementation.version>
     <usermanager.northbound.version>0.0.2-SNAPSHOT</usermanager.northbound.version>
     <usermanager.version>0.4.2-SNAPSHOT</usermanager.version>
         <artifactId>logback-core</artifactId>
         <version>${logback.version}</version>
       </dependency>
+      <dependency>
+        <groupId>com.codahale.metrics</groupId>
+        <artifactId>metrics-core</artifactId>
+        <version>${codahale.metrics.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.codahale.metrics</groupId>
+        <artifactId>metrics-graphite</artifactId>
+        <version>${codahale.metrics.version}</version>
+      </dependency>
       <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-annotations</artifactId>
         <artifactId>sal-dom-xsql</artifactId>
         <version>${mdsal.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-dom-xsql-config</artifactId>
+        <version>${mdsal.version}</version>
+        <classifier>config</classifier>
+        <type>xml</type>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal-core-api</artifactId>
         <artifactId>yang-data-composite-node</artifactId>
         <version>${yangtools.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-data-codec-gson</artifactId>
+        <version>${yangtools.version}</version>
+      </dependency>
 
       <!-- yangtools dependencies -->
       <dependency>
diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/RefreshingSCPModuleInfoRegistryTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/osgi/RefreshingSCPModuleInfoRegistryTest.java
new file mode 100644 (file)
index 0000000..79391d4
--- /dev/null
@@ -0,0 +1,46 @@
+package org.opendaylight.controller.config.manager.impl.osgi;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.config.manager.impl.osgi.mapping.RefreshingSCPModuleInfoRegistry;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.sal.binding.generator.api.ModuleInfoRegistry;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.*;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class RefreshingSCPModuleInfoRegistryTest {
+    @Test
+    public void testConstructor() throws Exception {
+        ModuleInfoRegistry reg = mock(ModuleInfoRegistry.class);
+        SchemaContextProvider prov = mock(SchemaContextProvider.class);
+        doReturn("string").when(prov).toString();
+
+        BundleContext ctxt = mock(BundleContext.class);
+        Dictionary dict = new Hashtable();
+        ServiceRegistration servReg = mock(ServiceRegistration.class);
+        doReturn(servReg).when(ctxt).registerService(Mockito.any(Class.class), Mockito.any(SchemaContextProvider.class), Mockito.any(Dictionary.class));
+        doReturn(servReg).when(ctxt).registerService(Mockito.anyString(), Mockito.any(Object.class), Mockito.any(Dictionary.class));
+        RefreshingSCPModuleInfoRegistry scpreg = new RefreshingSCPModuleInfoRegistry(reg, prov, ctxt);
+
+        YangModuleInfo modInfo = mock(YangModuleInfo.class);
+        doNothing().when(servReg).setProperties(null);
+        doNothing().when(servReg).unregister();
+        doReturn("").when(modInfo).toString();
+        ObjectRegistration<YangModuleInfo> ymi = mock(ObjectRegistration.class);
+        doReturn(ymi).when(reg).registerModuleInfo(modInfo);
+
+        scpreg.registerModuleInfo(modInfo);
+        scpreg.close();
+
+        Mockito.verify(servReg, Mockito.times(1)).setProperties(null);
+        Mockito.verify(servReg, Mockito.times(1)).unregister();
+    }
+}
index c2ac77a5d6f57b3ba24a581a700dead2fcc8a377..a644bf6ee835f0434ec6f4a1678dc48f3fcf9cf2 100644 (file)
@@ -92,6 +92,11 @@ ovsdb.listenPort=6640
 # default Openflow version = 1.0, we also support 1.3.
 # ovsdb.of.version=1.3
 
+# ovsdb can be configured with ml2 to perform l3 forwarding. When used in that scenario, the mac address of the default
+# gateway --on the external subnet-- is expected to be resolved from its inet address. The config below overrides that
+# specific arp/neighDiscovery lookup.
+# ovsdb.l3gateway.mac=00:00:5E:00:02:01
+
 # TLS configuration
 # To enable TLS, set secureChannelEnabled=true and specify the location of controller Java KeyStore and TrustStore files.
 # The Java KeyStore contains controller's private key and certificate. The Java TrustStore contains the trusted certificate
index fc8b4453eadc48f4fecdae144b29ddf822e9967d..fcb452f42239c98d838d580fbbf9e94ce623f89b 100644 (file)
       <groupId>org.opendaylight.controller.thirdparty</groupId>
       <artifactId>net.sf.jung2</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.thirdparty</groupId>
-      <artifactId>org.apache.catalina.filters.CorsFilter</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller.thirdparty</groupId>
       <artifactId>org.openflow.openflowj</artifactId>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>sal-restconf-broker</artifactId>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>sal-remoterpc-connector</artifactId>
-        </dependency>
 
 
         <dependency>
           <groupId>org.opendaylight.yangtools</groupId>
           <artifactId>yang-parser-impl</artifactId>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-data-codec-gson</artifactId>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.yangtools</groupId>
           <artifactId>yang-data-composite-node</artifactId>
           <artifactId>jeromq</artifactId>
           <version>0.3.1</version>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>sal-distributed-datastore</artifactId>
-        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>sal-clustering-config</artifactId>
                 <phase>generate-resources</phase>
                 <configuration>
                    <outputDirectory>${project.build.directory}/configuration</outputDirectory>
-                   <includeArtifactIds>sal-rest-connector-config,config-netty-config,md-sal-config,netconf-config,toaster-config,netconf-connector-config</includeArtifactIds>
-                   <includes>**\/*.xml</includes>
+                    <includeArtifactIds>sal-rest-connector-config,config-netty-config,md-sal-config,netconf-config,toaster-config,netconf-connector-config,sal-clustering-config</includeArtifactIds>
+                    <includes>**\/*.xml,**/*.conf</includes>
                    <excludeTransitive>true</excludeTransitive>
                    <ignorePermissions>false</ignorePermissions>
                 </configuration>
index b2fc3cb386ffa4525fb42dd3fae685c7b6a39e97..530e46e14a89e89fedee8657b19849cc9d0cfac4 100644 (file)
@@ -116,6 +116,11 @@ ovsdb.listenPort=6640
 # default Openflow version = 1.3, we also support 1.0.
 ovsdb.of.version=1.3
 
+# ovsdb can be configured with ml2 to perform l3 forwarding. When used in that scenario, the mac address of the default
+# gateway --on the external subnet-- is expected to be resolved from its inet address. The config below overrides that
+# specific arp/neighDiscovery lookup.
+# ovsdb.l3gateway.mac=00:00:5E:00:02:01
+
 # TLS configuration
 # To enable TLS, set secureChannelEnabled=true and specify the location of controller Java KeyStore and TrustStore files.
 # The Java KeyStore contains controller's private key and certificate. The Java TrustStore contains the trusted certificate
index 13be2336b6db94304d944b78ba912530bee25c5f..b032469b7f1403d9a6f9bdcfc172a982ada2ac41 100755 (executable)
@@ -112,6 +112,7 @@ while true ; do
         -Xmx*) jvmMaxMemory="$1"; shift;;
         -D*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
         -X*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
+        -J*) extraJVMOpts="${extraJVMOpts} -$(echo "$1" | cut -d'J' -f2)"; shift;;
         -agentpath:*) agentPath="$1"; shift;;
         "") break ;;
         *) echo "Unknown option $1"; unknown_option=1; break ;;
index be087abdb41099b9a5d8505ed20f7ac59624f531..b873f8a9fe060ff93c0279fbef0ad3cf59d0ab84 100644 (file)
@@ -14,6 +14,7 @@ import java.math.BigInteger;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
+import java.util.regex.Pattern;
 import org.opendaylight.controller.sal.common.util.Arguments;
 import org.opendaylight.controller.sal.core.AdvertisedBandwidth;
 import org.opendaylight.controller.sal.core.Bandwidth;
@@ -80,6 +81,12 @@ public final class NodeMapping {
 
     private final static Class<NodeConnector> NODECONNECTOR_CLASS = NodeConnector.class;
 
+    private final static Pattern COLON_NUMBERS_EOL = Pattern.compile(":[0-9]+$");
+
+    private final static Pattern NUMBERS_ONLY = Pattern.compile("[0-9]+");
+
+    private final static Pattern ALL_CHARS_TO_COLON = Pattern.compile("^.*:");
+
     private NodeMapping() {
         throw new UnsupportedOperationException("Utility class. Instantiation is not allowed.");
     }
@@ -182,15 +189,16 @@ public final class NodeMapping {
             return org.opendaylight.controller.sal.core.NodeConnector.SPECIALNODECONNECTORID;
         }
 
-        String nodeConnectorIdStripped = nodeConnectorId.getValue().replaceFirst("^.*:", "");
-        if (nodeConnectorIdStripped.matches("[0-9]+")) {
+        String nodeConnectorIdStripped = ALL_CHARS_TO_COLON.matcher(nodeConnectorId.getValue()).replaceFirst("");
+
+        if (NUMBERS_ONLY.matcher(nodeConnectorIdStripped).matches()) {
             Short nodeConnectorIdVal = null;
             try {
                 nodeConnectorIdVal = Short.valueOf(nodeConnectorIdStripped);
+                return nodeConnectorIdVal;
             } catch (NumberFormatException e) {
-                LOG.warn("nodeConnectorId not supported (short): {}", nodeConnectorIdStripped, e);
+                LOG.warn("nodeConnectorId not supported (long): {}", nodeConnectorIdStripped, e);
             }
-            return nodeConnectorIdVal;
         }
         return nodeConnectorIdStripped;
     }
@@ -198,7 +206,7 @@ public final class NodeMapping {
     public static NodeId toAdNodeId(final NodeConnectorId nodeConnectorId) {
         NodeId nodeId = null;
         if (nodeConnectorId != null) {
-            nodeId = new NodeId(nodeConnectorId.getValue().replaceFirst(":[0-9]+$", ""));
+            nodeId = new NodeId(COLON_NUMBERS_EOL.matcher(nodeConnectorId.getValue()).replaceFirst(""));
         }
         return nodeId;
     }
index c184c44d7d0fae3661632e3a3bb77f1d86ff879e..ce830eaa62d3e1f23c288f1969b1e79969252cf7 100644 (file)
 
     <!-- XSQL -->
     <module>sal-dom-xsql</module>
+    <module>sal-dom-xsql-config</module>
 
     <!-- Yang Test Models for MD-SAL -->
     <module>sal-test-model</module>
 
     <!-- Clustering -->
     <module>sal-remoterpc-connector</module>
-    <module>sal-dom-xsql-config</module>
   </modules>
 
   <build>
index 325005b239f83cbdf2a28bd7e01fbd1e88eb1ebe..98c81c267fae2c8dd5ec70ca9d663fc33b5e340c 100644 (file)
@@ -97,9 +97,8 @@
         <configuration>
           <instructions>
             <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
-            <Export-package></Export-package>
-            <Private-Package></Private-Package>
-            <Import-Package></Import-Package>
+            <Export-package>org.opendaylight.cluster.raft</Export-package>
+            <Import-Package>*</Import-Package>
           </instructions>
         </configuration>
       </plugin>
index cbd7ca2d70f5dc090a1e842b75c200cb0c1976b9..c4ff108611d9fbdb177f2ef4ace98bb030d69991 100644 (file)
@@ -12,14 +12,21 @@ import akka.actor.ActorRef;
 import akka.actor.Props;
 import akka.japi.Creator;
 import com.google.common.base.Optional;
+import com.google.protobuf.ByteString;
 import org.opendaylight.controller.cluster.example.messages.KeyValue;
 import org.opendaylight.controller.cluster.example.messages.KeyValueSaved;
 import org.opendaylight.controller.cluster.example.messages.PrintRole;
 import org.opendaylight.controller.cluster.example.messages.PrintState;
 import org.opendaylight.controller.cluster.raft.ConfigParams;
 import org.opendaylight.controller.cluster.raft.RaftActor;
+import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -82,14 +89,63 @@ public class ExampleActor extends RaftActor {
         }
     }
 
-    @Override protected Object createSnapshot() {
-        return state;
+    @Override protected void createSnapshot() {
+        ByteString bs = null;
+        try {
+            bs = fromObject(state);
+        } catch (Exception e) {
+            LOG.error("Exception in creating snapshot", e);
+        }
+        getSelf().tell(new CaptureSnapshotReply(bs), null);
     }
 
-    @Override protected void applySnapshot(Object snapshot) {
+    @Override protected void applySnapshot(ByteString snapshot) {
         state.clear();
-        state.putAll((HashMap) snapshot);
-        LOG.debug("Snapshot applied to state :" + ((HashMap) snapshot).size());
+        try {
+            state.putAll((HashMap) toObject(snapshot));
+        } catch (Exception e) {
+           LOG.error("Exception in applying snapshot", e);
+        }
+        LOG.debug("Snapshot applied to state :" + ((HashMap) state).size());
+    }
+
+    private ByteString fromObject(Object snapshot) throws Exception {
+        ByteArrayOutputStream b = null;
+        ObjectOutputStream o = null;
+        try {
+            b = new ByteArrayOutputStream();
+            o = new ObjectOutputStream(b);
+            o.writeObject(snapshot);
+            byte[] snapshotBytes = b.toByteArray();
+            return ByteString.copyFrom(snapshotBytes);
+        } finally {
+            if (o != null) {
+                o.flush();
+                o.close();
+            }
+            if (b != null) {
+                b.close();
+            }
+        }
+    }
+
+    private Object toObject(ByteString bs) throws ClassNotFoundException, IOException {
+        Object obj = null;
+        ByteArrayInputStream bis = null;
+        ObjectInputStream ois = null;
+        try {
+            bis = new ByteArrayInputStream(bs.toByteArray());
+            ois = new ObjectInputStream(bis);
+            obj = ois.readObject();
+        } finally {
+            if (bis != null) {
+                bis.close();
+            }
+            if (ois != null) {
+                ois.close();
+            }
+        }
+        return obj;
     }
 
     @Override protected void onStateChanged() {
index d11377dbcb359e58fdbbf3494a20ca6ded6565c4..6192cad2307b99896326619233bf9903f7aeb41a 100644 (file)
@@ -17,4 +17,9 @@ public class ExampleConfigParamsImpl extends DefaultConfigParamsImpl {
     public long getSnapshotBatchCount() {
         return 50;
     }
+
+    @Override
+    public int getSnapshotChunkSize() {
+        return 50;
+    }
 }
index fd6e192bf0497777de2643a1b3f28a2a76b72e42..978ea91089dbcb1a530c9d66f6878ffa06579e2d 100644 (file)
@@ -109,6 +109,8 @@ public class TestDriver {
                 td.printState();
             } else if (command.startsWith("printNodes")) {
                 td.printNodes();
+            } else {
+                System.out.println("Invalid command:" + command);
             }
 
         }
index b5b034afb9cf8edc7635cfca5509c93cbeb457b5..b436bce50061f98d0362ce3df4336c4279977d63 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.cluster.raft;
 
+import com.google.protobuf.ByteString;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -16,12 +18,18 @@ import java.util.List;
  */
 public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
 
-    protected final List<ReplicatedLogEntry> journal;
-    protected final Object snapshot;
+    protected List<ReplicatedLogEntry> journal;
+    protected ByteString snapshot;
     protected long snapshotIndex = -1;
     protected long snapshotTerm = -1;
 
-    public AbstractReplicatedLogImpl(Object state, long snapshotIndex,
+    // to be used for rollback during save snapshot failure
+    protected List<ReplicatedLogEntry> snapshottedJournal;
+    protected ByteString previousSnapshot;
+    protected long previousSnapshotIndex = -1;
+    protected long previousSnapshotTerm = -1;
+
+    public AbstractReplicatedLogImpl(ByteString state, long snapshotIndex,
         long snapshotTerm, List<ReplicatedLogEntry> unAppliedEntries) {
         this.snapshot = state;
         this.snapshotIndex = snapshotIndex;
@@ -137,11 +145,11 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
 
     @Override
     public boolean isInSnapshot(long logEntryIndex) {
-        return logEntryIndex <= snapshotIndex;
+        return logEntryIndex <= snapshotIndex && snapshotIndex != -1;
     }
 
     @Override
-    public Object getSnapshot() {
+    public ByteString getSnapshot() {
         return snapshot;
     }
 
@@ -160,4 +168,68 @@ public abstract class AbstractReplicatedLogImpl implements ReplicatedLog {
 
     @Override
     public abstract void removeFromAndPersist(long index);
+
+    @Override
+    public void setSnapshotIndex(long snapshotIndex) {
+        this.snapshotIndex = snapshotIndex;
+    }
+
+    @Override
+    public void setSnapshotTerm(long snapshotTerm) {
+        this.snapshotTerm = snapshotTerm;
+    }
+
+    @Override
+    public void setSnapshot(ByteString snapshot) {
+        this.snapshot = snapshot;
+    }
+
+    @Override
+    public void clear(int startIndex, int endIndex) {
+        journal.subList(startIndex, endIndex).clear();
+    }
+
+    @Override
+    public void snapshotPreCommit(ByteString snapshot, long snapshotCapturedIndex, long snapshotCapturedTerm) {
+        snapshottedJournal = new ArrayList<>(journal.size());
+
+        snapshottedJournal.addAll(journal.subList(0, (int)(snapshotCapturedIndex - snapshotIndex)));
+        clear(0, (int) (snapshotCapturedIndex - snapshotIndex));
+
+        previousSnapshotIndex = snapshotIndex;
+        setSnapshotIndex(snapshotCapturedIndex);
+
+        previousSnapshotTerm = snapshotTerm;
+        setSnapshotTerm(snapshotCapturedTerm);
+
+        previousSnapshot = getSnapshot();
+        setSnapshot(snapshot);
+    }
+
+    @Override
+    public void snapshotCommit() {
+        snapshottedJournal.clear();
+        snapshottedJournal = null;
+        previousSnapshotIndex = -1;
+        previousSnapshotTerm = -1;
+        previousSnapshot = null;
+    }
+
+    @Override
+    public void snapshotRollback() {
+        snapshottedJournal.addAll(journal);
+        journal.clear();
+        journal = snapshottedJournal;
+        snapshottedJournal = null;
+
+        snapshotIndex = previousSnapshotIndex;
+        previousSnapshotIndex = -1;
+
+        snapshotTerm = previousSnapshotTerm;
+        previousSnapshotTerm = -1;
+
+        snapshot = previousSnapshot;
+        previousSnapshot = null;
+
+    }
 }
index 4c6434aec457db0b4899973f36effd0b37e7d14a..ed6439d8c33bceb545927fd6c2f892665b160f8a 100644 (file)
@@ -52,4 +52,9 @@ public interface ConfigParams {
      * @return int
      */
     public int getElectionTimeVariance();
+
+    /**
+     * The size (in bytes) of the snapshot chunk sent from Leader
+     */
+    public int getSnapshotChunkSize();
 }
index 6432fa4811beb64ef13f6869e6e252289c2163be..75c237f5035e57abd61c839835ec3c78548a6157 100644 (file)
@@ -25,6 +25,8 @@ public class DefaultConfigParamsImpl implements ConfigParams {
      */
     private static final int ELECTION_TIME_MAX_VARIANCE = 100;
 
+    private final int SNAPSHOT_CHUNK_SIZE = 2048 * 1000; //2MB
+
 
     /**
      * The interval at which a heart beat message will be sent to the remote
@@ -58,4 +60,9 @@ public class DefaultConfigParamsImpl implements ConfigParams {
     public int getElectionTimeVariance() {
         return ELECTION_TIME_MAX_VARIANCE;
     }
+
+    @Override
+    public int getSnapshotChunkSize() {
+        return SNAPSHOT_CHUNK_SIZE;
+    }
 }
index 988789b4011e4f3ba9e9e9abe6b0c3009704c810..296ce2d24aaa24b3920d789697ddb784ccec7bea 100644 (file)
@@ -19,10 +19,14 @@ import akka.persistence.SaveSnapshotSuccess;
 import akka.persistence.SnapshotOffer;
 import akka.persistence.SnapshotSelectionCriteria;
 import akka.persistence.UntypedPersistentActor;
+import com.google.common.base.Optional;
+import com.google.protobuf.ByteString;
 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.Replicate;
-import com.google.common.base.Optional;
+import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat;
 import org.opendaylight.controller.cluster.raft.behaviors.Candidate;
 import org.opendaylight.controller.cluster.raft.behaviors.Follower;
 import org.opendaylight.controller.cluster.raft.behaviors.Leader;
@@ -31,10 +35,11 @@ import org.opendaylight.controller.cluster.raft.client.messages.AddRaftPeer;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
 import org.opendaylight.controller.cluster.raft.client.messages.RemoveRaftPeer;
+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 java.io.Serializable;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -98,6 +103,9 @@ public abstract class RaftActor extends UntypedPersistentActor {
      */
     private ReplicatedLogImpl replicatedLog = new ReplicatedLogImpl();
 
+    private CaptureSnapshot captureSnapshot = null;
+
+    private volatile boolean hasSnapshotCaptureInitiated = false;
 
     public RaftActor(String id, Map<String, String> peerAddresses) {
         this(id, peerAddresses, Optional.<ConfigParams>absent());
@@ -125,6 +133,7 @@ public abstract class RaftActor extends UntypedPersistentActor {
             replicatedLog = new ReplicatedLogImpl(snapshot);
 
             context.setReplicatedLog(replicatedLog);
+            context.setLastApplied(snapshot.getLastAppliedIndex());
 
             LOG.debug("Applied snapshot to replicatedLog. " +
                 "snapshotIndex={}, snapshotTerm={}, journal-size={}",
@@ -132,7 +141,7 @@ public abstract class RaftActor extends UntypedPersistentActor {
                 replicatedLog.size());
 
             // Apply the snapshot to the actors state
-            applySnapshot(snapshot.getState());
+            applySnapshot(ByteString.copyFrom(snapshot.getState()));
 
         } else if (message instanceof ReplicatedLogEntry) {
             replicatedLog.append((ReplicatedLogEntry) message);
@@ -164,7 +173,17 @@ public abstract class RaftActor extends UntypedPersistentActor {
                 applyState.getReplicatedLogEntry().getData());
 
         } else if(message instanceof ApplySnapshot ) {
-            applySnapshot(((ApplySnapshot) message).getSnapshot());
+            Snapshot snapshot = ((ApplySnapshot) message).getSnapshot();
+
+            LOG.debug("ApplySnapshot called on Follower Actor " +
+                "snapshotIndex:{}, snapshotTerm:{}", snapshot.getLastAppliedIndex(),
+                snapshot.getLastAppliedTerm());
+            applySnapshot(ByteString.copyFrom(snapshot.getState()));
+
+            //clears the followers log, sets the snapshot index to ensure adjusted-index works
+            replicatedLog = new ReplicatedLogImpl(snapshot);
+            context.setReplicatedLog(replicatedLog);
+            context.setLastApplied(snapshot.getLastAppliedIndex());
 
         } else if (message instanceof FindLeader) {
             getSender().tell(
@@ -174,13 +193,26 @@ public abstract class RaftActor extends UntypedPersistentActor {
 
         } else if (message instanceof SaveSnapshotSuccess) {
             SaveSnapshotSuccess success = (SaveSnapshotSuccess) message;
+            LOG.info("SaveSnapshotSuccess received for snapshot");
+
+            context.getReplicatedLog().snapshotCommit();
 
             // TODO: Not sure if we want to be this aggressive with trimming stuff
             trimPersistentData(success.metadata().sequenceNr());
 
         } else if (message instanceof SaveSnapshotFailure) {
+            SaveSnapshotFailure saveSnapshotFailure = (SaveSnapshotFailure) message;
+
+            LOG.info("saveSnapshotFailure.metadata():{}", saveSnapshotFailure.metadata().toString());
+            LOG.error(saveSnapshotFailure.cause(), "SaveSnapshotFailure received for snapshot Cause:");
 
-            // TODO: Handle failure in saving the snapshot
+            context.getReplicatedLog().snapshotRollback();
+
+            LOG.info("Replicated Log rollbacked. Snapshot will be attempted in the next cycle." +
+                "snapshotIndex:{}, snapshotTerm:{}, log-size:{}",
+                context.getReplicatedLog().getSnapshotIndex(),
+                context.getReplicatedLog().getSnapshotTerm(),
+                context.getReplicatedLog().size());
 
         } else if (message instanceof AddRaftPeer){
 
@@ -196,7 +228,25 @@ public abstract class RaftActor extends UntypedPersistentActor {
             RemoveRaftPeer rrp = (RemoveRaftPeer)message;
             context.removePeer(rrp.getName());
 
+        } else if (message instanceof CaptureSnapshot) {
+            LOG.debug("CaptureSnapshot received by actor");
+            CaptureSnapshot cs = (CaptureSnapshot)message;
+            captureSnapshot = cs;
+            createSnapshot();
+
+        } else if (message instanceof CaptureSnapshotReply){
+            LOG.debug("CaptureSnapshotReply received by actor");
+            CaptureSnapshotReply csr = (CaptureSnapshotReply) message;
+
+            ByteString stateInBytes = csr.getSnapshot();
+            LOG.debug("CaptureSnapshotReply stateInBytes size:{}", stateInBytes.size());
+            handleCaptureSnapshotReply(stateInBytes);
+
         } else {
+            if (!(message instanceof AppendEntriesMessages.AppendEntries)
+                && !(message instanceof AppendEntriesReply) && !(message instanceof SendHeartBeat)) {
+                LOG.debug("onReceiveCommand: message:" + message.getClass());
+            }
 
             RaftState state =
                 currentBehavior.handleMessage(getSender(), message);
@@ -344,7 +394,7 @@ public abstract class RaftActor extends UntypedPersistentActor {
      *
      * @return The current state of the actor
      */
-    protected abstract Object createSnapshot();
+    protected abstract void createSnapshot();
 
     /**
      * This method will be called by the RaftActor during recovery to
@@ -356,7 +406,7 @@ public abstract class RaftActor extends UntypedPersistentActor {
      *
      * @param snapshot A snapshot of the state of the actor
      */
-    protected abstract void applySnapshot(Object snapshot);
+    protected abstract void applySnapshot(ByteString snapshot);
 
     /**
      * This method will be called by the RaftActor when the state of the
@@ -423,11 +473,39 @@ public abstract class RaftActor extends UntypedPersistentActor {
         return peerAddress;
     }
 
+    private void handleCaptureSnapshotReply(ByteString stateInBytes) {
+        // create a snapshot object from the state provided and save it
+        // when snapshot is saved async, SaveSnapshotSuccess is raised.
+
+        Snapshot sn = Snapshot.create(stateInBytes.toByteArray(),
+            context.getReplicatedLog().getFrom(captureSnapshot.getLastAppliedIndex() + 1),
+            captureSnapshot.getLastIndex(), captureSnapshot.getLastTerm(),
+            captureSnapshot.getLastAppliedIndex(), captureSnapshot.getLastAppliedTerm());
+
+        saveSnapshot(sn);
+
+        LOG.info("Persisting of snapshot done:{}", 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,
+
+        context.getReplicatedLog().snapshotPreCommit(stateInBytes,
+            captureSnapshot.getLastAppliedIndex(),
+            captureSnapshot.getLastAppliedTerm());
+
+        LOG.info("Removed in-memory snapshotted entries, adjusted snaphsotIndex:{} " +
+            "and term:{}", captureSnapshot.getLastAppliedIndex(),
+            captureSnapshot.getLastAppliedTerm());
+
+        captureSnapshot = null;
+        hasSnapshotCaptureInitiated = false;
+    }
+
 
     private class ReplicatedLogImpl extends AbstractReplicatedLogImpl {
 
         public ReplicatedLogImpl(Snapshot snapshot) {
-            super(snapshot.getState(),
+            super(ByteString.copyFrom(snapshot.getState()),
                 snapshot.getLastAppliedIndex(), snapshot.getLastAppliedTerm(),
                 snapshot.getUnAppliedEntries());
         }
@@ -476,8 +554,10 @@ public abstract class RaftActor extends UntypedPersistentActor {
             persist(replicatedLogEntry,
                 new Procedure<ReplicatedLogEntry>() {
                     public void apply(ReplicatedLogEntry evt) throws Exception {
-                        // FIXME : Tentatively create a snapshot every hundred thousand entries. To be tuned.
-                        if (journal.size() > context.getConfigParams().getSnapshotBatchCount()) {
+                        // when a snaphsot is being taken, captureSnapshot != null
+                        if (hasSnapshotCaptureInitiated == false &&
+                            journal.size() % context.getConfigParams().getSnapshotBatchCount() == 0) {
+
                             LOG.info("Initiating Snapshot Capture..");
                             long lastAppliedIndex = -1;
                             long lastAppliedTerm = -1;
@@ -493,26 +573,11 @@ public abstract class RaftActor extends UntypedPersistentActor {
                             LOG.debug("Snapshot Capture lastAppliedIndex:{}", lastAppliedIndex);
                             LOG.debug("Snapshot Capture lastAppliedTerm:{}", lastAppliedTerm);
 
-                            // create a snapshot object from the state provided and save it
-                            // when snapshot is saved async, SaveSnapshotSuccess is raised.
-                            Snapshot sn = Snapshot.create(createSnapshot(),
-                                getFrom(context.getLastApplied() + 1),
-                                lastIndex(), lastTerm(), lastAppliedIndex,
-                                lastAppliedTerm);
-                            saveSnapshot(sn);
-
-                            LOG.info("Persisting of snapshot done:{}", 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,
-                            // TODO: damage-recovery to be done on failure
-                            journal.subList(0, (int) (lastAppliedIndex - snapshotIndex)).clear();
-                            snapshotIndex = lastAppliedIndex;
-                            snapshotTerm = lastAppliedTerm;
-
-                            LOG.info("Removed in-memory snapshotted entries, " +
-                                "adjusted snaphsotIndex:{}" +
-                                "and term:{}", snapshotIndex, lastAppliedTerm);
+                            // send a CaptureSnapshot to self to make the expensive operation async.
+                            getSelf().tell(new CaptureSnapshot(
+                                lastIndex(), lastTerm(), lastAppliedIndex, lastAppliedTerm),
+                                null);
+                            hasSnapshotCaptureInitiated = true;
                         }
                         // Send message for replication
                         if (clientActor != null) {
@@ -542,65 +607,6 @@ public abstract class RaftActor extends UntypedPersistentActor {
     }
 
 
-    private static class Snapshot implements Serializable {
-        private final Object state;
-        private final List<ReplicatedLogEntry> unAppliedEntries;
-        private final long lastIndex;
-        private final long lastTerm;
-        private final long lastAppliedIndex;
-        private final long lastAppliedTerm;
-
-        private Snapshot(Object state,
-            List<ReplicatedLogEntry> unAppliedEntries, long lastIndex,
-            long lastTerm, long lastAppliedIndex, long lastAppliedTerm) {
-            this.state = state;
-            this.unAppliedEntries = unAppliedEntries;
-            this.lastIndex = lastIndex;
-            this.lastTerm = lastTerm;
-            this.lastAppliedIndex = lastAppliedIndex;
-            this.lastAppliedTerm = lastAppliedTerm;
-        }
-
-
-        public static Snapshot create(Object state,
-            List<ReplicatedLogEntry> entries, long lastIndex, long lastTerm,
-            long lastAppliedIndex, long lastAppliedTerm) {
-            return new Snapshot(state, entries, lastIndex, lastTerm,
-                lastAppliedIndex, lastAppliedTerm);
-        }
-
-        public Object getState() {
-            return state;
-        }
-
-        public List<ReplicatedLogEntry> getUnAppliedEntries() {
-            return unAppliedEntries;
-        }
-
-        public long getLastTerm() {
-            return lastTerm;
-        }
-
-        public long getLastAppliedIndex() {
-            return lastAppliedIndex;
-        }
-
-        public long getLastAppliedTerm() {
-            return lastAppliedTerm;
-        }
-
-        public String getLogMessage() {
-            StringBuilder sb = new StringBuilder();
-            return sb.append("Snapshot={")
-                .append("lastTerm:" + this.getLastTerm()  + ", ")
-                .append("LastAppliedIndex:" + this.getLastAppliedIndex()  + ", ")
-                .append("LastAppliedTerm:" + this.getLastAppliedTerm()  + ", ")
-                .append("UnAppliedEntries size:" + this.getUnAppliedEntries().size()  + "}")
-                .toString();
-
-        }
-    }
-
     private class ElectionTermImpl implements ElectionTerm {
         /**
          * Identifier of the actor whose election term information this is
index e6e160bc02bf1fd72305325aefc91a1ac2a9fac0..c17f5448c6e256a97c4f7134959bb6c2d88a0971 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.controller.cluster.raft;
 
+import com.google.protobuf.ByteString;
+
 import java.util.List;
 
 /**
@@ -118,7 +120,7 @@ public interface ReplicatedLog {
      *
      * @return an object representing the snapshot if it exists. null otherwise
      */
-    Object getSnapshot();
+    ByteString getSnapshot();
 
     /**
      * Get the index of the snapshot
@@ -134,4 +136,49 @@ public interface ReplicatedLog {
      * otherwise
      */
     long getSnapshotTerm();
+
+    /**
+     * sets the snapshot index in the replicated log
+     * @param snapshotIndex
+     */
+    void setSnapshotIndex(long snapshotIndex);
+
+    /**
+     * sets snapshot term
+     * @param snapshotTerm
+     */
+    public void setSnapshotTerm(long snapshotTerm);
+
+    /**
+     * sets the snapshot in bytes
+     * @param snapshot
+     */
+    public void setSnapshot(ByteString snapshot);
+
+    /**
+     * Clears the journal entries with startIndex(inclusive) and endIndex (exclusive)
+     * @param startIndex
+     * @param endIndex
+     */
+    public void clear(int startIndex, int endIndex);
+
+    /**
+     * Handles all the bookkeeping in order to perform a rollback in the
+     * event of SaveSnapshotFailure
+     * @param snapshot
+     * @param snapshotCapturedIndex
+     * @param snapshotCapturedTerm
+     */
+    public void snapshotPreCommit(ByteString snapshot,
+        long snapshotCapturedIndex, long snapshotCapturedTerm);
+
+    /**
+     * Sets the Replicated log to state after snapshot success.
+     */
+    public void snapshotCommit();
+
+    /**
+     * Restores the replicated log to a state in the event of a save snapshot failure
+     */
+    public void snapshotRollback();
 }
index 374e0fa9ba766cfe0417347fc4d6a4602d21fcdb..2f5ba48f9258d9a47ebf62ac98966db5d1055d99 100644 (file)
@@ -9,12 +9,16 @@
 package org.opendaylight.controller.cluster.raft;
 
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
+import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot;
 
 public class SerializationUtils {
 
     public static Object fromSerializable(Object serializable){
         if(serializable.getClass().equals(AppendEntries.SERIALIZABLE_CLASS)){
             return AppendEntries.fromSerializable(serializable);
+
+        } else if (serializable.getClass().equals(InstallSnapshot.SERIALIZABLE_CLASS)) {
+            return InstallSnapshot.fromSerializable(serializable);
         }
         return serializable;
     }
diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/Snapshot.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/Snapshot.java
new file mode 100644 (file)
index 0000000..8e0fcca
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.raft;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+public class Snapshot implements Serializable {
+    private final byte[] state;
+    private final List<ReplicatedLogEntry> unAppliedEntries;
+    private final long lastIndex;
+    private final long lastTerm;
+    private final long lastAppliedIndex;
+    private final long lastAppliedTerm;
+
+    private Snapshot(byte[] state,
+        List<ReplicatedLogEntry> unAppliedEntries, long lastIndex,
+        long lastTerm, long lastAppliedIndex, long lastAppliedTerm) {
+        this.state = state;
+        this.unAppliedEntries = unAppliedEntries;
+        this.lastIndex = lastIndex;
+        this.lastTerm = lastTerm;
+        this.lastAppliedIndex = lastAppliedIndex;
+        this.lastAppliedTerm = lastAppliedTerm;
+    }
+
+
+    public static Snapshot create(byte[] state,
+        List<ReplicatedLogEntry> entries, long lastIndex, long lastTerm,
+        long lastAppliedIndex, long lastAppliedTerm) {
+        return new Snapshot(state, entries, lastIndex, lastTerm,
+            lastAppliedIndex, lastAppliedTerm);
+    }
+
+    public byte[] getState() {
+        return state;
+    }
+
+    public List<ReplicatedLogEntry> getUnAppliedEntries() {
+        return unAppliedEntries;
+    }
+
+    public long getLastTerm() {
+        return lastTerm;
+    }
+
+    public long getLastAppliedIndex() {
+        return lastAppliedIndex;
+    }
+
+    public long getLastAppliedTerm() {
+        return lastAppliedTerm;
+    }
+
+    public long getLastIndex() {
+        return this.lastIndex;
+    }
+
+    public String getLogMessage() {
+        StringBuilder sb = new StringBuilder();
+        return sb.append("Snapshot={")
+            .append("lastTerm:" + this.getLastTerm() + ", ")
+            .append("lastIndex:" + this.getLastIndex()  + ", ")
+            .append("LastAppliedIndex:" + this.getLastAppliedIndex()  + ", ")
+            .append("LastAppliedTerm:" + this.getLastAppliedTerm()  + ", ")
+            .append("UnAppliedEntries size:" + this.getUnAppliedEntries().size()  + "}")
+            .toString();
+
+    }
+}
index 9739fb2f1b0ccb42e5fcd0446e5769194797be31..c356804223c696e83f10c73e17da35d63d419c85 100644 (file)
@@ -8,16 +8,21 @@
 
 package org.opendaylight.controller.cluster.raft.base.messages;
 
+import org.opendaylight.controller.cluster.raft.Snapshot;
+
 import java.io.Serializable;
 
+/**
+ * Internal message, issued by follower to its actor
+ */
 public class ApplySnapshot implements Serializable {
-    private final Object snapshot;
+    private final Snapshot snapshot;
 
-    public ApplySnapshot(Object snapshot) {
+    public ApplySnapshot(Snapshot snapshot) {
         this.snapshot = snapshot;
     }
 
-    public Object getSnapshot() {
+    public Snapshot getSnapshot() {
         return snapshot;
     }
 }
diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/CaptureSnapshot.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/CaptureSnapshot.java
new file mode 100644 (file)
index 0000000..bb86e1a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.cluster.raft.base.messages;
+
+public class CaptureSnapshot {
+    private long lastAppliedIndex;
+    private long lastAppliedTerm;
+    private long lastIndex;
+    private long lastTerm;
+
+    public CaptureSnapshot(long lastIndex, long lastTerm,
+        long lastAppliedIndex, long lastAppliedTerm) {
+        this.lastIndex = lastIndex;
+        this.lastTerm = lastTerm;
+        this.lastAppliedIndex = lastAppliedIndex;
+        this.lastAppliedTerm = lastAppliedTerm;
+    }
+
+    public long getLastAppliedIndex() {
+        return lastAppliedIndex;
+    }
+
+    public long getLastAppliedTerm() {
+        return lastAppliedTerm;
+    }
+
+    public long getLastIndex() {
+        return lastIndex;
+    }
+
+    public long getLastTerm() {
+        return lastTerm;
+    }
+}
diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/CaptureSnapshotReply.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/base/messages/CaptureSnapshotReply.java
new file mode 100644 (file)
index 0000000..96150db
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.raft.base.messages;
+
+import com.google.protobuf.ByteString;
+
+public class CaptureSnapshotReply {
+    private ByteString snapshot;
+
+    public CaptureSnapshotReply(ByteString snapshot) {
+        this.snapshot = snapshot;
+    }
+
+    public ByteString getSnapshot() {
+        return snapshot;
+    }
+
+    public void setSnapshot(ByteString snapshot) {
+        this.snapshot = snapshot;
+    }
+}
index 251a13d583ec444ac4ca0c1cc028831feeb48958..7e896fed29c4889f6aec5ce39436a1970a50e03b 100644 (file)
@@ -305,6 +305,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      * @param index a log index that is known to be committed
      */
     protected void applyLogToStateMachine(final long index) {
+        long newLastApplied = context.getLastApplied();
         // Now maybe we apply to the state machine
         for (long i = context.getLastApplied() + 1;
              i < index + 1; i++) {
@@ -322,15 +323,19 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
             if (replicatedLogEntry != null) {
                 actor().tell(new ApplyState(clientActor, identifier,
                     replicatedLogEntry), actor());
+                newLastApplied = i;
             } else {
+                //if one index is not present in the log, no point in looping
+                // around as the rest wont be present either
                 context.getLogger().error(
-                    "Missing index " + i + " from log. Cannot apply state.");
+                    "Missing index {} from log. Cannot apply state. Ignoring {} to {}", i, i, index );
+                break;
             }
         }
         // Send a local message to the local RaftActor (it's derived class to be
         // specific to apply the log to it's index)
-        context.getLogger().debug("Setting last applied to {}", index);
-        context.setLastApplied(index);
+        context.getLogger().debug("Setting last applied to {}", newLastApplied);
+        context.setLastApplied(newLastApplied);
     }
 
     protected Object fromSerializableMessage(Object serializable){
index 54e0494b9da65305729afcf00686e3102c31dd00..610fdc987fde7a1a51491ef25dc2f764011b9eda 100644 (file)
@@ -9,17 +9,22 @@
 package org.opendaylight.controller.cluster.raft.behaviors;
 
 import akka.actor.ActorRef;
+import com.google.protobuf.ByteString;
 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.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.RequestVoteReply;
 
+import java.util.ArrayList;
+
 /**
  * The behavior of a RaftActor in the Follower state
  * <p/>
@@ -31,6 +36,8 @@ import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
  * </ul>
  */
 public class Follower extends AbstractRaftActorBehavior {
+    private ByteString snapshotChunksCollected = ByteString.EMPTY;
+
     public Follower(RaftActorContext context) {
         super(context);
 
@@ -106,6 +113,9 @@ public class Follower extends AbstractRaftActorBehavior {
         if (outOfSync) {
             // We found that the log was out of sync so just send a negative
             // reply and return
+            context.getLogger().debug("Follower is out-of-sync, " +
+                "so sending negative reply, lastIndex():{}, lastTerm():{}",
+                lastIndex(), lastTerm());
             sender.tell(
                 new AppendEntriesReply(context.getId(), currentTerm(), false,
                     lastIndex(), lastTerm()), actor()
@@ -191,7 +201,13 @@ public class Follower extends AbstractRaftActorBehavior {
 
         // If commitIndex > lastApplied: increment lastApplied, apply
         // log[lastApplied] to state machine (§5.3)
-        if (appendEntries.getLeaderCommit() > context.getLastApplied()) {
+        // 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.getLogger().debug("applyLogToStateMachine, " +
+                "appendEntries.getLeaderCommit():{}," +
+                "context.getLastApplied():{}, lastIndex():{}",
+                appendEntries.getLeaderCommit(), context.getLastApplied(), lastIndex());
             applyLogToStateMachine(appendEntries.getLeaderCommit());
         }
 
@@ -234,7 +250,7 @@ public class Follower extends AbstractRaftActorBehavior {
 
         } else if (message instanceof InstallSnapshot) {
             InstallSnapshot installSnapshot = (InstallSnapshot) message;
-            actor().tell(new ApplySnapshot(installSnapshot.getData()), actor());
+            handleInstallSnapshot(sender, installSnapshot);
         }
 
         scheduleElection(electionDuration());
@@ -242,6 +258,47 @@ public class Follower extends AbstractRaftActorBehavior {
         return super.handleMessage(sender, message);
     }
 
+    private void handleInstallSnapshot(ActorRef sender, InstallSnapshot installSnapshot) {
+        context.getLogger().debug("InstallSnapshot received by follower " +
+            "datasize:{} , Chunk:{}/{}", installSnapshot.getData().size(),
+            installSnapshot.getChunkIndex(), installSnapshot.getTotalChunks());
+
+        try {
+            if (installSnapshot.getChunkIndex() == installSnapshot.getTotalChunks()) {
+                // this is the last chunk, create a snapshot object and apply
+
+                snapshotChunksCollected = snapshotChunksCollected.concat(installSnapshot.getData());
+                context.getLogger().debug("Last chunk received: snapshotChunksCollected.size:{}",
+                    snapshotChunksCollected.size());
+
+                Snapshot snapshot = Snapshot.create(snapshotChunksCollected.toByteArray(),
+                    new ArrayList<ReplicatedLogEntry>(),
+                    installSnapshot.getLastIncludedIndex(),
+                    installSnapshot.getLastIncludedTerm(),
+                    installSnapshot.getLastIncludedIndex(),
+                    installSnapshot.getLastIncludedTerm());
+
+                actor().tell(new ApplySnapshot(snapshot), actor());
+
+            } else {
+                // we have more to go
+                snapshotChunksCollected = snapshotChunksCollected.concat(installSnapshot.getData());
+                context.getLogger().debug("Chunk={},snapshotChunksCollected.size:{}",
+                    installSnapshot.getChunkIndex(), snapshotChunksCollected.size());
+            }
+
+            sender.tell(new InstallSnapshotReply(
+                currentTerm(), context.getId(), installSnapshot.getChunkIndex(),
+                true), actor());
+
+        } catch (Exception e) {
+            context.getLogger().error("Exception in InstallSnapshot of follower", 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());
+        }
+    }
+
     @Override public void close() throws Exception {
         stopElection();
     }
index 234f9db664e4d43e833e4e354e3d3045094dd381..90948ffef7d8a5e1341bb8aede6b03ccf8dae344 100644 (file)
@@ -12,6 +12,7 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
 import akka.actor.Cancellable;
 import com.google.common.base.Preconditions;
+import com.google.protobuf.ByteString;
 import org.opendaylight.controller.cluster.raft.ClientRequestTracker;
 import org.opendaylight.controller.cluster.raft.ClientRequestTrackerImpl;
 import org.opendaylight.controller.cluster.raft.FollowerLogInformation;
@@ -30,6 +31,7 @@ import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
 import scala.concurrent.duration.FiniteDuration;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -64,8 +66,9 @@ import java.util.concurrent.atomic.AtomicLong;
 public class Leader extends AbstractRaftActorBehavior {
 
 
-    private final Map<String, FollowerLogInformation> followerToLog =
+    protected final Map<String, FollowerLogInformation> followerToLog =
         new HashMap();
+    protected final Map<String, FollowerToSnapshot> mapFollowerToSnapshot = new HashMap<>();
 
     private final Set<String> followers;
 
@@ -246,16 +249,48 @@ public class Leader extends AbstractRaftActorBehavior {
         return super.handleMessage(sender, message);
     }
 
-    private void handleInstallSnapshotReply(InstallSnapshotReply message) {
-        InstallSnapshotReply reply = message;
+    private void handleInstallSnapshotReply(InstallSnapshotReply reply) {
         String followerId = reply.getFollowerId();
-        FollowerLogInformation followerLogInformation =
-            followerToLog.get(followerId);
+        FollowerToSnapshot followerToSnapshot =
+            mapFollowerToSnapshot.get(followerId);
+
+        if (followerToSnapshot != null &&
+            followerToSnapshot.getChunkIndex() == reply.getChunkIndex()) {
+
+            if (reply.isSuccess()) {
+                if(followerToSnapshot.isLastChunk(reply.getChunkIndex())) {
+                    //this was the last chunk reply
+                    context.getLogger().debug("InstallSnapshotReply received, " +
+                        "last chunk received, Chunk:{}. Follower:{} Setting nextIndex:{}",
+                        reply.getChunkIndex(), followerId,
+                        context.getReplicatedLog().getSnapshotIndex() + 1);
+
+                    FollowerLogInformation followerLogInformation =
+                        followerToLog.get(followerId);
+                    followerLogInformation.setMatchIndex(
+                        context.getReplicatedLog().getSnapshotIndex());
+                    followerLogInformation.setNextIndex(
+                        context.getReplicatedLog().getSnapshotIndex() + 1);
+                    mapFollowerToSnapshot.remove(followerId);
+                    context.getLogger().debug("followerToLog.get(followerId).getNextIndex().get()=" +
+                        followerToLog.get(followerId).getNextIndex().get());
+
+                } else {
+                    followerToSnapshot.markSendStatus(true);
+                }
+            } else {
+                context.getLogger().info("InstallSnapshotReply received, " +
+                    "sending snapshot chunk failed, Will retry, Chunk:{}",
+                    reply.getChunkIndex());
+                followerToSnapshot.markSendStatus(false);
+            }
 
-        followerLogInformation
-            .setMatchIndex(context.getReplicatedLog().getSnapshotIndex());
-        followerLogInformation
-            .setNextIndex(context.getReplicatedLog().getSnapshotIndex() + 1);
+        } else {
+            context.getLogger().error("ERROR!!" +
+                "FollowerId in InstallSnapshotReply not known to Leader" +
+                " or Chunk Index in InstallSnapshotReply not matching {} != {}",
+                followerToSnapshot.getChunkIndex(), reply.getChunkIndex() );
+        }
     }
 
     private void replicate(Replicate replicate) {
@@ -282,30 +317,56 @@ public class Leader extends AbstractRaftActorBehavior {
     private void sendAppendEntries() {
         // Send an AppendEntries to all followers
         for (String followerId : followers) {
-            ActorSelection followerActor =
-                context.getPeerActorSelection(followerId);
+            ActorSelection followerActor = context.getPeerActorSelection(followerId);
 
             if (followerActor != null) {
-                FollowerLogInformation followerLogInformation =
-                    followerToLog.get(followerId);
-
-                long nextIndex = followerLogInformation.getNextIndex().get();
-
+                FollowerLogInformation followerLogInformation = followerToLog.get(followerId);
+                long followerNextIndex = followerLogInformation.getNextIndex().get();
                 List<ReplicatedLogEntry> entries = Collections.emptyList();
 
-                if (context.getReplicatedLog().isPresent(nextIndex)) {
-                    // FIXME : Sending one entry at a time
-                    entries =
-                        context.getReplicatedLog().getFrom(nextIndex, 1);
+                if (mapFollowerToSnapshot.get(followerId) != null) {
+                    if (mapFollowerToSnapshot.get(followerId).canSendNextChunk()) {
+                        sendSnapshotChunk(followerActor, followerId);
+                    }
+
+                } else {
+
+                    if (context.getReplicatedLog().isPresent(followerNextIndex)) {
+                        // FIXME : Sending one entry at a time
+                        entries = context.getReplicatedLog().getFrom(followerNextIndex, 1);
+
+                        followerActor.tell(
+                            new AppendEntries(currentTerm(), context.getId(),
+                                prevLogIndex(followerNextIndex),
+                                prevLogTerm(followerNextIndex), entries,
+                                context.getCommitIndex()).toSerializable(),
+                            actor()
+                        );
+
+                    } else {
+                        // if the followers next index is not present in the leaders log, then snapshot should be sent
+                        long leaderSnapShotIndex = context.getReplicatedLog().getSnapshotIndex();
+                        long leaderLastIndex = context.getReplicatedLog().lastIndex();
+                        if (followerNextIndex >= 0 && leaderLastIndex >= followerNextIndex ) {
+                            // if the follower is just not starting and leader's index
+                            // is more than followers index
+                            context.getLogger().debug("SendInstallSnapshot to follower:{}," +
+                                "follower-nextIndex:{}, leader-snapshot-index:{},  " +
+                                "leader-last-index:{}", followerId,
+                                followerNextIndex, leaderSnapShotIndex, leaderLastIndex);
+
+                            actor().tell(new SendInstallSnapshot(), actor());
+                        } else {
+                            followerActor.tell(
+                                new AppendEntries(currentTerm(), context.getId(),
+                                    prevLogIndex(followerNextIndex),
+                                    prevLogTerm(followerNextIndex), entries,
+                                    context.getCommitIndex()).toSerializable(),
+                                actor()
+                            );
+                        }
+                    }
                 }
-
-                followerActor.tell(
-                    new AppendEntries(currentTerm(), context.getId(),
-                        prevLogIndex(nextIndex),
-                        prevLogTerm(nextIndex), entries,
-                        context.getCommitIndex()).toSerializable(),
-                    actor()
-                );
             }
         }
     }
@@ -326,21 +387,55 @@ public class Leader extends AbstractRaftActorBehavior {
 
                 long nextIndex = followerLogInformation.getNextIndex().get();
 
-                if (!context.getReplicatedLog().isPresent(nextIndex) && context
-                    .getReplicatedLog().isInSnapshot(nextIndex)) {
-                    followerActor.tell(
-                        new InstallSnapshot(currentTerm(), context.getId(),
-                            context.getReplicatedLog().getSnapshotIndex(),
-                            context.getReplicatedLog().getSnapshotTerm(),
-                            context.getReplicatedLog().getSnapshot()
-                        ),
-                        actor()
-                    );
+                if (!context.getReplicatedLog().isPresent(nextIndex) &&
+                    context.getReplicatedLog().isInSnapshot(nextIndex)) {
+                    sendSnapshotChunk(followerActor, followerId);
                 }
             }
         }
     }
 
+    /**
+     *  Sends a snapshot chunk to a given follower
+     *  InstallSnapshot should qualify as a heartbeat too.
+     */
+    private void sendSnapshotChunk(ActorSelection followerActor, String followerId) {
+        try {
+            followerActor.tell(
+                new InstallSnapshot(currentTerm(), context.getId(),
+                    context.getReplicatedLog().getSnapshotIndex(),
+                    context.getReplicatedLog().getSnapshotTerm(),
+                    getNextSnapshotChunk(followerId,
+                        context.getReplicatedLog().getSnapshot()),
+                    mapFollowerToSnapshot.get(followerId).incrementChunkIndex(),
+                    mapFollowerToSnapshot.get(followerId).getTotalChunks()
+                ).toSerializable(),
+                actor()
+            );
+            context.getLogger().info("InstallSnapshot sent to follower {}, Chunk: {}/{}",
+                followerActor.path(), mapFollowerToSnapshot.get(followerId).getChunkIndex(),
+                mapFollowerToSnapshot.get(followerId).getTotalChunks());
+        } catch (IOException e) {
+            context.getLogger().error("InstallSnapshot failed for Leader.", e);
+        }
+    }
+
+    /**
+     * Acccepts snaphot as ByteString, enters into map for future chunks
+     * creates and return a ByteString chunk
+     */
+    private ByteString getNextSnapshotChunk(String followerId, ByteString snapshotBytes) throws IOException {
+        FollowerToSnapshot followerToSnapshot = mapFollowerToSnapshot.get(followerId);
+        if (followerToSnapshot == null) {
+            followerToSnapshot = new FollowerToSnapshot(snapshotBytes);
+            mapFollowerToSnapshot.put(followerId, followerToSnapshot);
+        }
+        ByteString nextChunk = followerToSnapshot.getNextChunk();
+        context.getLogger().debug("Leader's snapshot nextChunk size:{}", nextChunk.size());
+
+        return nextChunk;
+    }
+
     private RaftState sendHeartBeat() {
         if (followers.size() > 0) {
             sendAppendEntries();
@@ -410,4 +505,97 @@ public class Leader extends AbstractRaftActorBehavior {
         return context.getId();
     }
 
+    /**
+     * Encapsulates the snapshot bytestring and handles the logic of sending
+     * snapshot chunks
+     */
+    protected class FollowerToSnapshot {
+        private ByteString snapshotBytes;
+        private int offset = 0;
+        // the next snapshot chunk is sent only if the replyReceivedForOffset matches offset
+        private int replyReceivedForOffset;
+        // if replyStatus is false, the previous chunk is attempted
+        private boolean replyStatus = false;
+        private int chunkIndex;
+        private int totalChunks;
+
+        public FollowerToSnapshot(ByteString snapshotBytes) {
+            this.snapshotBytes = snapshotBytes;
+            replyReceivedForOffset = -1;
+            chunkIndex = 1;
+            int size = snapshotBytes.size();
+            totalChunks = ( size / context.getConfigParams().getSnapshotChunkSize()) +
+                ((size % context.getConfigParams().getSnapshotChunkSize()) > 0 ? 1 : 0);
+            context.getLogger().debug("Snapshot {} bytes, total chunks to send:{}",
+                size, totalChunks);
+        }
+
+        public ByteString getSnapshotBytes() {
+            return snapshotBytes;
+        }
+
+        public int incrementOffset() {
+            if(replyStatus) {
+                // if prev chunk failed, we would want to sent the same chunk again
+                offset = offset + context.getConfigParams().getSnapshotChunkSize();
+            }
+            return offset;
+        }
+
+        public int incrementChunkIndex() {
+            if (replyStatus) {
+                // if prev chunk failed, we would want to sent the same chunk again
+                chunkIndex =  chunkIndex + 1;
+            }
+            return chunkIndex;
+        }
+
+        public int getChunkIndex() {
+            return chunkIndex;
+        }
+
+        public int getTotalChunks() {
+            return totalChunks;
+        }
+
+        public boolean canSendNextChunk() {
+            // we only send a false if a chunk is sent but we have not received a reply yet
+            return replyReceivedForOffset == offset;
+        }
+
+        public boolean isLastChunk(int chunkIndex) {
+            return totalChunks == chunkIndex;
+        }
+
+        public void markSendStatus(boolean success) {
+            if (success) {
+                // if the chunk sent was successful
+                replyReceivedForOffset = offset;
+                replyStatus = true;
+            } else {
+                // if the chunk sent was failure
+                replyReceivedForOffset = offset;
+                replyStatus = false;
+            }
+        }
+
+        public ByteString getNextChunk() {
+            int snapshotLength = getSnapshotBytes().size();
+            int start = incrementOffset();
+            int size = context.getConfigParams().getSnapshotChunkSize();
+            if (context.getConfigParams().getSnapshotChunkSize() > snapshotLength) {
+                size = snapshotLength;
+            } else {
+                if ((start + context.getConfigParams().getSnapshotChunkSize()) > snapshotLength) {
+                    size = snapshotLength - start;
+                }
+            }
+
+            context.getLogger().debug("length={}, offset={},size={}",
+                snapshotLength, start, size);
+            return getSnapshotBytes().substring(start, start + size);
+
+        }
+    }
+
 }
index 888854fa71eaf4f745e11456c7b09349a7d8a443..9d40fa3d9edb3858969797e929776ddcba424333 100644 (file)
@@ -8,19 +8,29 @@
 
 package org.opendaylight.controller.cluster.raft.messages;
 
+import com.google.protobuf.ByteString;
+import org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages;
+
 public class InstallSnapshot extends AbstractRaftRPC {
 
+    public static final Class SERIALIZABLE_CLASS = InstallSnapshotMessages.InstallSnapshot.class;
+
     private final String leaderId;
     private final long lastIncludedIndex;
     private final long lastIncludedTerm;
-    private final Object data;
+    private final ByteString data;
+    private final int chunkIndex;
+    private final int totalChunks;
 
-    public InstallSnapshot(long term, String leaderId, long lastIncludedIndex, long lastIncludedTerm, Object data) {
+    public InstallSnapshot(long term, String leaderId, long lastIncludedIndex,
+        long lastIncludedTerm, ByteString data, int chunkIndex, int totalChunks) {
         super(term);
         this.leaderId = leaderId;
         this.lastIncludedIndex = lastIncludedIndex;
         this.lastIncludedTerm = lastIncludedTerm;
         this.data = data;
+        this.chunkIndex = chunkIndex;
+        this.totalChunks = totalChunks;
     }
 
     public String getLeaderId() {
@@ -35,7 +45,38 @@ public class InstallSnapshot extends AbstractRaftRPC {
         return lastIncludedTerm;
     }
 
-    public Object getData() {
+    public ByteString getData() {
         return data;
     }
+
+    public int getChunkIndex() {
+        return chunkIndex;
+    }
+
+    public int getTotalChunks() {
+        return totalChunks;
+    }
+
+    public <T extends Object> Object toSerializable(){
+        return InstallSnapshotMessages.InstallSnapshot.newBuilder()
+            .setLeaderId(this.getLeaderId())
+            .setChunkIndex(this.getChunkIndex())
+            .setData(this.getData())
+            .setLastIncludedIndex(this.getLastIncludedIndex())
+            .setLastIncludedTerm(this.getLastIncludedTerm())
+            .setTotalChunks(this.getTotalChunks()).build();
+
+    }
+
+    public static InstallSnapshot fromSerializable (Object o) {
+        InstallSnapshotMessages.InstallSnapshot from =
+            (InstallSnapshotMessages.InstallSnapshot) o;
+
+        InstallSnapshot installSnapshot = new InstallSnapshot(from.getTerm(),
+            from.getLeaderId(), from.getLastIncludedIndex(),
+            from.getLastIncludedTerm(), from.getData(),
+            from.getChunkIndex(), from.getTotalChunks());
+
+        return installSnapshot;
+    }
 }
index 85b89b70ae2b84c8ab26fcb7e16ba041fbd2040a..d293a47c8efdd1521afa4652f7a6a100e4c692ab 100644 (file)
@@ -13,13 +13,26 @@ public class InstallSnapshotReply extends AbstractRaftRPC {
     // The followerId - this will be used to figure out which follower is
     // responding
     private final String followerId;
+    private final int chunkIndex;
+    private boolean success;
 
-    protected InstallSnapshotReply(long term, String followerId) {
+    public InstallSnapshotReply(long term, String followerId, int chunkIndex,
+        boolean success) {
         super(term);
         this.followerId = followerId;
+        this.chunkIndex = chunkIndex;
+        this.success = success;
     }
 
     public String getFollowerId() {
         return followerId;
     }
+
+    public int getChunkIndex() {
+        return chunkIndex;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
 }
diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/protobuff/messages/InstallSnapshotMessages.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/protobuff/messages/InstallSnapshotMessages.java
new file mode 100644 (file)
index 0000000..e801ae1
--- /dev/null
@@ -0,0 +1,1015 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: InstallSnapshot.proto
+
+package org.opendaylight.controller.cluster.raft.protobuff.messages;
+
+public final class InstallSnapshotMessages {
+  private InstallSnapshotMessages() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistry registry) {
+  }
+  public interface InstallSnapshotOrBuilder
+      extends com.google.protobuf.MessageOrBuilder {
+
+    // optional int64 term = 1;
+    /**
+     * <code>optional int64 term = 1;</code>
+     */
+    boolean hasTerm();
+    /**
+     * <code>optional int64 term = 1;</code>
+     */
+    long getTerm();
+
+    // optional string leaderId = 2;
+    /**
+     * <code>optional string leaderId = 2;</code>
+     */
+    boolean hasLeaderId();
+    /**
+     * <code>optional string leaderId = 2;</code>
+     */
+    java.lang.String getLeaderId();
+    /**
+     * <code>optional string leaderId = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getLeaderIdBytes();
+
+    // optional int64 lastIncludedIndex = 3;
+    /**
+     * <code>optional int64 lastIncludedIndex = 3;</code>
+     */
+    boolean hasLastIncludedIndex();
+    /**
+     * <code>optional int64 lastIncludedIndex = 3;</code>
+     */
+    long getLastIncludedIndex();
+
+    // optional int64 lastIncludedTerm = 4;
+    /**
+     * <code>optional int64 lastIncludedTerm = 4;</code>
+     */
+    boolean hasLastIncludedTerm();
+    /**
+     * <code>optional int64 lastIncludedTerm = 4;</code>
+     */
+    long getLastIncludedTerm();
+
+    // optional bytes data = 5;
+    /**
+     * <code>optional bytes data = 5;</code>
+     */
+    boolean hasData();
+    /**
+     * <code>optional bytes data = 5;</code>
+     */
+    com.google.protobuf.ByteString getData();
+
+    // optional int32 chunkIndex = 6;
+    /**
+     * <code>optional int32 chunkIndex = 6;</code>
+     */
+    boolean hasChunkIndex();
+    /**
+     * <code>optional int32 chunkIndex = 6;</code>
+     */
+    int getChunkIndex();
+
+    // optional int32 totalChunks = 7;
+    /**
+     * <code>optional int32 totalChunks = 7;</code>
+     */
+    boolean hasTotalChunks();
+    /**
+     * <code>optional int32 totalChunks = 7;</code>
+     */
+    int getTotalChunks();
+  }
+  /**
+   * Protobuf type {@code org.opendaylight.controller.cluster.raft.InstallSnapshot}
+   */
+  public static final class InstallSnapshot extends
+      com.google.protobuf.GeneratedMessage
+      implements InstallSnapshotOrBuilder {
+    // Use InstallSnapshot.newBuilder() to construct.
+    private InstallSnapshot(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private InstallSnapshot(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+    private static final InstallSnapshot defaultInstance;
+    public static InstallSnapshot getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public InstallSnapshot getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final com.google.protobuf.UnknownFieldSet unknownFields;
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+        getUnknownFields() {
+      return this.unknownFields;
+    }
+    private InstallSnapshot(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 8: {
+              bitField0_ |= 0x00000001;
+              term_ = input.readInt64();
+              break;
+            }
+            case 18: {
+              bitField0_ |= 0x00000002;
+              leaderId_ = input.readBytes();
+              break;
+            }
+            case 24: {
+              bitField0_ |= 0x00000004;
+              lastIncludedIndex_ = input.readInt64();
+              break;
+            }
+            case 32: {
+              bitField0_ |= 0x00000008;
+              lastIncludedTerm_ = input.readInt64();
+              break;
+            }
+            case 42: {
+              bitField0_ |= 0x00000010;
+              data_ = input.readBytes();
+              break;
+            }
+            case 48: {
+              bitField0_ |= 0x00000020;
+              chunkIndex_ = input.readInt32();
+              break;
+            }
+            case 56: {
+              bitField0_ |= 0x00000040;
+              totalChunks_ = input.readInt32();
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot.class, org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot.Builder.class);
+    }
+
+    public static com.google.protobuf.Parser<InstallSnapshot> PARSER =
+        new com.google.protobuf.AbstractParser<InstallSnapshot>() {
+      public InstallSnapshot parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new InstallSnapshot(input, extensionRegistry);
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<InstallSnapshot> getParserForType() {
+      return PARSER;
+    }
+
+    private int bitField0_;
+    // optional int64 term = 1;
+    public static final int TERM_FIELD_NUMBER = 1;
+    private long term_;
+    /**
+     * <code>optional int64 term = 1;</code>
+     */
+    public boolean hasTerm() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional int64 term = 1;</code>
+     */
+    public long getTerm() {
+      return term_;
+    }
+
+    // optional string leaderId = 2;
+    public static final int LEADERID_FIELD_NUMBER = 2;
+    private java.lang.Object leaderId_;
+    /**
+     * <code>optional string leaderId = 2;</code>
+     */
+    public boolean hasLeaderId() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional string leaderId = 2;</code>
+     */
+    public java.lang.String getLeaderId() {
+      java.lang.Object ref = leaderId_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          leaderId_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string leaderId = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getLeaderIdBytes() {
+      java.lang.Object ref = leaderId_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        leaderId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    // optional int64 lastIncludedIndex = 3;
+    public static final int LASTINCLUDEDINDEX_FIELD_NUMBER = 3;
+    private long lastIncludedIndex_;
+    /**
+     * <code>optional int64 lastIncludedIndex = 3;</code>
+     */
+    public boolean hasLastIncludedIndex() {
+      return ((bitField0_ & 0x00000004) == 0x00000004);
+    }
+    /**
+     * <code>optional int64 lastIncludedIndex = 3;</code>
+     */
+    public long getLastIncludedIndex() {
+      return lastIncludedIndex_;
+    }
+
+    // optional int64 lastIncludedTerm = 4;
+    public static final int LASTINCLUDEDTERM_FIELD_NUMBER = 4;
+    private long lastIncludedTerm_;
+    /**
+     * <code>optional int64 lastIncludedTerm = 4;</code>
+     */
+    public boolean hasLastIncludedTerm() {
+      return ((bitField0_ & 0x00000008) == 0x00000008);
+    }
+    /**
+     * <code>optional int64 lastIncludedTerm = 4;</code>
+     */
+    public long getLastIncludedTerm() {
+      return lastIncludedTerm_;
+    }
+
+    // optional bytes data = 5;
+    public static final int DATA_FIELD_NUMBER = 5;
+    private com.google.protobuf.ByteString data_;
+    /**
+     * <code>optional bytes data = 5;</code>
+     */
+    public boolean hasData() {
+      return ((bitField0_ & 0x00000010) == 0x00000010);
+    }
+    /**
+     * <code>optional bytes data = 5;</code>
+     */
+    public com.google.protobuf.ByteString getData() {
+      return data_;
+    }
+
+    // optional int32 chunkIndex = 6;
+    public static final int CHUNKINDEX_FIELD_NUMBER = 6;
+    private int chunkIndex_;
+    /**
+     * <code>optional int32 chunkIndex = 6;</code>
+     */
+    public boolean hasChunkIndex() {
+      return ((bitField0_ & 0x00000020) == 0x00000020);
+    }
+    /**
+     * <code>optional int32 chunkIndex = 6;</code>
+     */
+    public int getChunkIndex() {
+      return chunkIndex_;
+    }
+
+    // optional int32 totalChunks = 7;
+    public static final int TOTALCHUNKS_FIELD_NUMBER = 7;
+    private int totalChunks_;
+    /**
+     * <code>optional int32 totalChunks = 7;</code>
+     */
+    public boolean hasTotalChunks() {
+      return ((bitField0_ & 0x00000040) == 0x00000040);
+    }
+    /**
+     * <code>optional int32 totalChunks = 7;</code>
+     */
+    public int getTotalChunks() {
+      return totalChunks_;
+    }
+
+    private void initFields() {
+      term_ = 0L;
+      leaderId_ = "";
+      lastIncludedIndex_ = 0L;
+      lastIncludedTerm_ = 0L;
+      data_ = com.google.protobuf.ByteString.EMPTY;
+      chunkIndex_ = 0;
+      totalChunks_ = 0;
+    }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized != -1) return isInitialized == 1;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeInt64(1, term_);
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBytes(2, getLeaderIdBytes());
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        output.writeInt64(3, lastIncludedIndex_);
+      }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        output.writeInt64(4, lastIncludedTerm_);
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        output.writeBytes(5, data_);
+      }
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        output.writeInt32(6, chunkIndex_);
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        output.writeInt32(7, totalChunks_);
+      }
+      getUnknownFields().writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt64Size(1, term_);
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, getLeaderIdBytes());
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt64Size(3, lastIncludedIndex_);
+      }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt64Size(4, lastIncludedTerm_);
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(5, data_);
+      }
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(6, chunkIndex_);
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(7, totalChunks_);
+      }
+      size += getUnknownFields().getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
+    }
+
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code org.opendaylight.controller.cluster.raft.InstallSnapshot}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder>
+       implements org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshotOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot.class, org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot.Builder.class);
+      }
+
+      // Construct using org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+        }
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        term_ = 0L;
+        bitField0_ = (bitField0_ & ~0x00000001);
+        leaderId_ = "";
+        bitField0_ = (bitField0_ & ~0x00000002);
+        lastIncludedIndex_ = 0L;
+        bitField0_ = (bitField0_ & ~0x00000004);
+        lastIncludedTerm_ = 0L;
+        bitField0_ = (bitField0_ & ~0x00000008);
+        data_ = com.google.protobuf.ByteString.EMPTY;
+        bitField0_ = (bitField0_ & ~0x00000010);
+        chunkIndex_ = 0;
+        bitField0_ = (bitField0_ & ~0x00000020);
+        totalChunks_ = 0;
+        bitField0_ = (bitField0_ & ~0x00000040);
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_descriptor;
+      }
+
+      public org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot getDefaultInstanceForType() {
+        return org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot.getDefaultInstance();
+      }
+
+      public org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot build() {
+        org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot buildPartial() {
+        org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot result = new org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.term_ = term_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.leaderId_ = leaderId_;
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000004;
+        }
+        result.lastIncludedIndex_ = lastIncludedIndex_;
+        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+          to_bitField0_ |= 0x00000008;
+        }
+        result.lastIncludedTerm_ = lastIncludedTerm_;
+        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
+          to_bitField0_ |= 0x00000010;
+        }
+        result.data_ = data_;
+        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+          to_bitField0_ |= 0x00000020;
+        }
+        result.chunkIndex_ = chunkIndex_;
+        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
+          to_bitField0_ |= 0x00000040;
+        }
+        result.totalChunks_ = totalChunks_;
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot) {
+          return mergeFrom((org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot other) {
+        if (other == org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot.getDefaultInstance()) return this;
+        if (other.hasTerm()) {
+          setTerm(other.getTerm());
+        }
+        if (other.hasLeaderId()) {
+          bitField0_ |= 0x00000002;
+          leaderId_ = other.leaderId_;
+          onChanged();
+        }
+        if (other.hasLastIncludedIndex()) {
+          setLastIncludedIndex(other.getLastIncludedIndex());
+        }
+        if (other.hasLastIncludedTerm()) {
+          setLastIncludedTerm(other.getLastIncludedTerm());
+        }
+        if (other.hasData()) {
+          setData(other.getData());
+        }
+        if (other.hasChunkIndex()) {
+          setChunkIndex(other.getChunkIndex());
+        }
+        if (other.hasTotalChunks()) {
+          setTotalChunks(other.getTotalChunks());
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages.InstallSnapshot) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      // optional int64 term = 1;
+      private long term_ ;
+      /**
+       * <code>optional int64 term = 1;</code>
+       */
+      public boolean hasTerm() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional int64 term = 1;</code>
+       */
+      public long getTerm() {
+        return term_;
+      }
+      /**
+       * <code>optional int64 term = 1;</code>
+       */
+      public Builder setTerm(long value) {
+        bitField0_ |= 0x00000001;
+        term_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int64 term = 1;</code>
+       */
+      public Builder clearTerm() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        term_ = 0L;
+        onChanged();
+        return this;
+      }
+
+      // optional string leaderId = 2;
+      private java.lang.Object leaderId_ = "";
+      /**
+       * <code>optional string leaderId = 2;</code>
+       */
+      public boolean hasLeaderId() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional string leaderId = 2;</code>
+       */
+      public java.lang.String getLeaderId() {
+        java.lang.Object ref = leaderId_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          leaderId_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string leaderId = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getLeaderIdBytes() {
+        java.lang.Object ref = leaderId_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          leaderId_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string leaderId = 2;</code>
+       */
+      public Builder setLeaderId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        leaderId_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string leaderId = 2;</code>
+       */
+      public Builder clearLeaderId() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        leaderId_ = getDefaultInstance().getLeaderId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string leaderId = 2;</code>
+       */
+      public Builder setLeaderIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        leaderId_ = value;
+        onChanged();
+        return this;
+      }
+
+      // optional int64 lastIncludedIndex = 3;
+      private long lastIncludedIndex_ ;
+      /**
+       * <code>optional int64 lastIncludedIndex = 3;</code>
+       */
+      public boolean hasLastIncludedIndex() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
+      }
+      /**
+       * <code>optional int64 lastIncludedIndex = 3;</code>
+       */
+      public long getLastIncludedIndex() {
+        return lastIncludedIndex_;
+      }
+      /**
+       * <code>optional int64 lastIncludedIndex = 3;</code>
+       */
+      public Builder setLastIncludedIndex(long value) {
+        bitField0_ |= 0x00000004;
+        lastIncludedIndex_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int64 lastIncludedIndex = 3;</code>
+       */
+      public Builder clearLastIncludedIndex() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        lastIncludedIndex_ = 0L;
+        onChanged();
+        return this;
+      }
+
+      // optional int64 lastIncludedTerm = 4;
+      private long lastIncludedTerm_ ;
+      /**
+       * <code>optional int64 lastIncludedTerm = 4;</code>
+       */
+      public boolean hasLastIncludedTerm() {
+        return ((bitField0_ & 0x00000008) == 0x00000008);
+      }
+      /**
+       * <code>optional int64 lastIncludedTerm = 4;</code>
+       */
+      public long getLastIncludedTerm() {
+        return lastIncludedTerm_;
+      }
+      /**
+       * <code>optional int64 lastIncludedTerm = 4;</code>
+       */
+      public Builder setLastIncludedTerm(long value) {
+        bitField0_ |= 0x00000008;
+        lastIncludedTerm_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int64 lastIncludedTerm = 4;</code>
+       */
+      public Builder clearLastIncludedTerm() {
+        bitField0_ = (bitField0_ & ~0x00000008);
+        lastIncludedTerm_ = 0L;
+        onChanged();
+        return this;
+      }
+
+      // optional bytes data = 5;
+      private com.google.protobuf.ByteString data_ = com.google.protobuf.ByteString.EMPTY;
+      /**
+       * <code>optional bytes data = 5;</code>
+       */
+      public boolean hasData() {
+        return ((bitField0_ & 0x00000010) == 0x00000010);
+      }
+      /**
+       * <code>optional bytes data = 5;</code>
+       */
+      public com.google.protobuf.ByteString getData() {
+        return data_;
+      }
+      /**
+       * <code>optional bytes data = 5;</code>
+       */
+      public Builder setData(com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000010;
+        data_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bytes data = 5;</code>
+       */
+      public Builder clearData() {
+        bitField0_ = (bitField0_ & ~0x00000010);
+        data_ = getDefaultInstance().getData();
+        onChanged();
+        return this;
+      }
+
+      // optional int32 chunkIndex = 6;
+      private int chunkIndex_ ;
+      /**
+       * <code>optional int32 chunkIndex = 6;</code>
+       */
+      public boolean hasChunkIndex() {
+        return ((bitField0_ & 0x00000020) == 0x00000020);
+      }
+      /**
+       * <code>optional int32 chunkIndex = 6;</code>
+       */
+      public int getChunkIndex() {
+        return chunkIndex_;
+      }
+      /**
+       * <code>optional int32 chunkIndex = 6;</code>
+       */
+      public Builder setChunkIndex(int value) {
+        bitField0_ |= 0x00000020;
+        chunkIndex_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int32 chunkIndex = 6;</code>
+       */
+      public Builder clearChunkIndex() {
+        bitField0_ = (bitField0_ & ~0x00000020);
+        chunkIndex_ = 0;
+        onChanged();
+        return this;
+      }
+
+      // optional int32 totalChunks = 7;
+      private int totalChunks_ ;
+      /**
+       * <code>optional int32 totalChunks = 7;</code>
+       */
+      public boolean hasTotalChunks() {
+        return ((bitField0_ & 0x00000040) == 0x00000040);
+      }
+      /**
+       * <code>optional int32 totalChunks = 7;</code>
+       */
+      public int getTotalChunks() {
+        return totalChunks_;
+      }
+      /**
+       * <code>optional int32 totalChunks = 7;</code>
+       */
+      public Builder setTotalChunks(int value) {
+        bitField0_ |= 0x00000040;
+        totalChunks_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int32 totalChunks = 7;</code>
+       */
+      public Builder clearTotalChunks() {
+        bitField0_ = (bitField0_ & ~0x00000040);
+        totalChunks_ = 0;
+        onChanged();
+        return this;
+      }
+
+      // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.cluster.raft.InstallSnapshot)
+    }
+
+    static {
+      defaultInstance = new InstallSnapshot(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:org.opendaylight.controller.cluster.raft.InstallSnapshot)
+  }
+
+  private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_fieldAccessorTable;
+
+  public static com.google.protobuf.Descriptors.FileDescriptor
+      getDescriptor() {
+    return descriptor;
+  }
+  private static com.google.protobuf.Descriptors.FileDescriptor
+      descriptor;
+  static {
+    java.lang.String[] descriptorData = {
+      "\n\025InstallSnapshot.proto\022(org.opendayligh" +
+      "t.controller.cluster.raft\"\235\001\n\017InstallSna" +
+      "pshot\022\014\n\004term\030\001 \001(\003\022\020\n\010leaderId\030\002 \001(\t\022\031\n" +
+      "\021lastIncludedIndex\030\003 \001(\003\022\030\n\020lastIncluded" +
+      "Term\030\004 \001(\003\022\014\n\004data\030\005 \001(\014\022\022\n\nchunkIndex\030\006" +
+      " \001(\005\022\023\n\013totalChunks\030\007 \001(\005BX\n;org.openday" +
+      "light.controller.cluster.raft.protobuff." +
+      "messagesB\027InstallSnapshotMessagesH\001"
+    };
+    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
+      new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
+        public com.google.protobuf.ExtensionRegistry assignDescriptors(
+            com.google.protobuf.Descriptors.FileDescriptor root) {
+          descriptor = root;
+          internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_descriptor =
+            getDescriptor().getMessageTypes().get(0);
+          internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_fieldAccessorTable = new
+            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+              internal_static_org_opendaylight_controller_cluster_raft_InstallSnapshot_descriptor,
+              new java.lang.String[] { "Term", "LeaderId", "LastIncludedIndex", "LastIncludedTerm", "Data", "ChunkIndex", "TotalChunks", });
+          return null;
+        }
+      };
+    com.google.protobuf.Descriptors.FileDescriptor
+      .internalBuildGeneratedFileFrom(descriptorData,
+        new com.google.protobuf.Descriptors.FileDescriptor[] {
+        }, assigner);
+  }
+
+  // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/resources/InstallSnapshot.proto b/opendaylight/md-sal/sal-akka-raft/src/main/resources/InstallSnapshot.proto
new file mode 100644 (file)
index 0000000..14f821b
--- /dev/null
@@ -0,0 +1,15 @@
+package org.opendaylight.controller.cluster.raft;
+
+option java_package = "org.opendaylight.controller.cluster.raft.protobuff.messages";
+option java_outer_classname = "InstallSnapshotMessages";
+option optimize_for = SPEED;
+
+message InstallSnapshot {
+    optional int64 term = 1;
+    optional string leaderId = 2;
+    optional int64 lastIncludedIndex = 3;
+    optional int64 lastIncludedTerm = 4;
+    optional bytes data = 5;
+    optional int32 chunkIndex = 6;
+    optional int32 totalChunks = 7;
+}
index ea3c9e759d51744fb2dd36212bf8372e2f06f0c8..ca34a34ca49337783ec7fda8a9b9966fba1f16ac 100644 (file)
@@ -14,17 +14,14 @@ import akka.actor.ActorSystem;
 import akka.actor.Props;
 import akka.event.Logging;
 import akka.event.LoggingAdapter;
+import com.google.common.base.Preconditions;
 import com.google.protobuf.GeneratedMessage;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
 import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages;
 import org.opendaylight.controller.protobuff.messages.cluster.raft.test.MockPayloadMessages;
-import com.google.common.base.Preconditions;
 
 import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 public class MockRaftActorContext implements RaftActorContext {
@@ -37,6 +34,7 @@ public class MockRaftActorContext implements RaftActorContext {
     private final ElectionTerm electionTerm;
     private ReplicatedLog replicatedLog;
     private Map<String, String> peerAddresses = new HashMap();
+    private ConfigParams configParams;
 
     public MockRaftActorContext(){
         electionTerm = null;
@@ -79,6 +77,8 @@ public class MockRaftActorContext implements RaftActorContext {
             }
         };
 
+        configParams = new DefaultConfigParamsImpl();
+
         initReplicatedLog();
     }
 
@@ -179,118 +179,21 @@ public class MockRaftActorContext implements RaftActorContext {
 
     @Override
     public ConfigParams getConfigParams() {
-        return new DefaultConfigParamsImpl();
+        return configParams;
     }
 
-    public static class SimpleReplicatedLog implements ReplicatedLog {
-        private final List<ReplicatedLogEntry> log = new ArrayList<>();
-
-        @Override public ReplicatedLogEntry get(long index) {
-            if(index >= log.size() || index < 0){
-                return null;
-            }
-            return log.get((int) index);
-        }
-
-        @Override public ReplicatedLogEntry last() {
-            if(log.size() == 0){
-                return null;
-            }
-            return log.get(log.size()-1);
-        }
-
-        @Override public long lastIndex() {
-            if(log.size() == 0){
-                return -1;
-            }
-
-            return last().getIndex();
-        }
-
-        @Override public long lastTerm() {
-            if(log.size() == 0){
-                return -1;
-            }
-
-            return last().getTerm();
-        }
-
-        @Override public void removeFrom(long index) {
-            if(index >= log.size() || index < 0){
-                return;
-            }
-
-            log.subList((int) index, log.size()).clear();
-            //log.remove((int) index);
-        }
-
-        @Override public void removeFromAndPersist(long index) {
-            removeFrom(index);
-        }
-
-        @Override public void append(ReplicatedLogEntry replicatedLogEntry) {
-            log.add(replicatedLogEntry);
-        }
+    public void setConfigParams(ConfigParams configParams) {
+        this.configParams = configParams;
+    }
 
+    public static class SimpleReplicatedLog extends AbstractReplicatedLogImpl {
         @Override public void appendAndPersist(
             ReplicatedLogEntry replicatedLogEntry) {
             append(replicatedLogEntry);
         }
 
-        @Override public List<ReplicatedLogEntry> getFrom(long index) {
-            if(index >= log.size() || index < 0){
-                return Collections.EMPTY_LIST;
-            }
-            List<ReplicatedLogEntry> entries = new ArrayList<>();
-            for(int i=(int) index ; i < log.size() ; i++) {
-                entries.add(get(i));
-            }
-            return entries;
-        }
-
-        @Override public List<ReplicatedLogEntry> getFrom(long index, int max) {
-            if(index >= log.size() || index < 0){
-                return Collections.EMPTY_LIST;
-            }
-            List<ReplicatedLogEntry> entries = new ArrayList<>();
-            int maxIndex = (int) index + max;
-            if(maxIndex > log.size()){
-                maxIndex = log.size();
-            }
-
-            for(int i=(int) index ; i < maxIndex ; i++) {
-                entries.add(get(i));
-            }
-            return entries;
-
-        }
-
-        @Override public long size() {
-            return log.size();
-        }
-
-        @Override public boolean isPresent(long index) {
-            if(index >= log.size() || index < 0){
-                return false;
-            }
-
-            return true;
-        }
-
-        @Override public boolean isInSnapshot(long index) {
-            return false;
-        }
-
-        @Override public Object getSnapshot() {
-            return null;
-        }
-
-        @Override public long getSnapshotIndex() {
-            return -1;
-        }
-
-        @Override public long getSnapshotTerm() {
-            return -1;
+        @Override public void removeFromAndPersist(long index) {
+            removeFrom(index);
         }
     }
 
index ff0ffeb271b55b38455901d03cb31871620b078c..12123db12995061901a39a264c79f0237d78d00a 100644 (file)
@@ -6,6 +6,7 @@ import akka.actor.Props;
 import akka.event.Logging;
 import akka.japi.Creator;
 import akka.testkit.JavaTestKit;
+import com.google.protobuf.ByteString;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
@@ -39,11 +40,11 @@ public class RaftActorTest extends AbstractActorTest {
             Object data) {
         }
 
-        @Override protected Object createSnapshot() {
+        @Override protected void createSnapshot() {
             throw new UnsupportedOperationException("createSnapshot");
         }
 
-        @Override protected void applySnapshot(Object snapshot) {
+        @Override protected void applySnapshot(ByteString snapshot) {
             throw new UnsupportedOperationException("applySnapshot");
         }
 
index c5a81aa1c9225ea03fa548bf1950d5e73a7e3329..227d1effa7e9b8b3bb65932fe8c25b1a2eecdbf5 100644 (file)
@@ -158,17 +158,18 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
                 createActorContext();
 
             context.setLastApplied(100);
-            setLastLogEntry((MockRaftActorContext) context, 0, 0, new MockRaftActorContext.MockPayload(""));
+            setLastLogEntry((MockRaftActorContext) context, 1, 100, new MockRaftActorContext.MockPayload(""));
+            ((MockRaftActorContext) context).getReplicatedLog().setSnapshotIndex(99);
 
             List<ReplicatedLogEntry> entries =
                 Arrays.asList(
-                    (ReplicatedLogEntry) new MockRaftActorContext.MockReplicatedLogEntry(100, 101,
+                    (ReplicatedLogEntry) new MockRaftActorContext.MockReplicatedLogEntry(2, 101,
                         new MockRaftActorContext.MockPayload("foo"))
                 );
 
             // The new commitIndex is 101
             AppendEntries appendEntries =
-                new AppendEntries(100, "leader-1", 0, 0, entries, 101);
+                new AppendEntries(2, "leader-1", 100, 1, entries, 101);
 
             RaftState raftState =
                 createBehavior(context).handleMessage(getRef(), appendEntries);
index 17c22a134a9a7f26e08998930b2609b128f40c21..73c9f96b82a0a582f4cf5e61b5d68c488f9bc198 100644 (file)
@@ -1,24 +1,40 @@
 package org.opendaylight.controller.cluster.raft.behaviors;
 
 import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
 import akka.actor.Props;
 import akka.testkit.JavaTestKit;
-import junit.framework.Assert;
+import com.google.protobuf.ByteString;
+import org.junit.Assert;
 import org.junit.Test;
+import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
+import org.opendaylight.controller.cluster.raft.FollowerLogInformation;
+import org.opendaylight.controller.cluster.raft.FollowerLogInformationImpl;
 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.ReplicatedLogImplEntry;
+import org.opendaylight.controller.cluster.raft.SerializationUtils;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
 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.messages.AppendEntries;
+import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot;
+import org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply;
+import org.opendaylight.controller.cluster.raft.protobuff.messages.InstallSnapshotMessages;
 import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 public class LeaderTest extends AbstractRaftActorBehaviorTest {
 
@@ -82,8 +98,6 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                     assertEquals("match", out);
 
                 }
-
-
             };
         }};
     }
@@ -194,18 +208,372 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                     assertEquals("match", out);
 
                 }
+            };
+        }};
+    }
+
+    @Test
+    public void testSendInstallSnapshot() {
+        new LeaderTestKit(getSystem()) {{
+
+            new Within(duration("1 seconds")) {
+                protected void run() {
+                    ActorRef followerActor = getTestActor();
+
+                    Map<String, String> peerAddresses = new HashMap();
+                    peerAddresses.put(followerActor.path().toString(),
+                        followerActor.path().toString());
+
+
+                    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");
+
+                    //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().setSnapshot(
+                        toByteString(leadersSnapshot));
+                    actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+                    actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+
+                    MockLeader leader = new MockLeader(actorContext);
+                    // set the follower info in leader
+                    leader.addToFollowerToLog(followerActor.path().toString(), followersLastIndex, -1);
+
+                    // new entry
+                    ReplicatedLogImplEntry entry =
+                        new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
+                            new MockRaftActorContext.MockPayload("D"));
+
+                    // this should invoke a sendinstallsnapshot as followersLastIndex < snapshotIndex
+                    RaftState raftState = leader.handleMessage(
+                        senderActor, new Replicate(null, "state-id", entry));
+
+                    assertEquals(RaftState.Leader, raftState);
+
+                    // we might receive some heartbeat messages, so wait till we SendInstallSnapshot
+                    Boolean[] matches = new ReceiveWhile<Boolean>(Boolean.class, duration("2 seconds")) {
+                        @Override
+                        protected Boolean match(Object o) throws Exception {
+                            if (o instanceof SendInstallSnapshot) {
+                                return true;
+                            }
+                            return false;
+                        }
+                    }.get();
+
+                    boolean sendInstallSnapshotReceived = false;
+                    for (Boolean b: matches) {
+                        sendInstallSnapshotReceived = b | sendInstallSnapshotReceived;
+                    }
+
+                    assertTrue(sendInstallSnapshotReceived);
+
+                }
+            };
+        }};
+    }
+
+    @Test
+    public void testInstallSnapshot() {
+        new LeaderTestKit(getSystem()) {{
+
+            new Within(duration("1 seconds")) {
+                protected void run() {
+                    ActorRef followerActor = getTestActor();
+
+                    Map<String, String> peerAddresses = new HashMap();
+                    peerAddresses.put(followerActor.path().toString(),
+                        followerActor.path().toString());
+
+                    MockRaftActorContext actorContext =
+                        (MockRaftActorContext) createActorContext();
+                    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().setSnapshot(toByteString(leadersSnapshot));
+                    actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+                    actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+
+                    actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
+
+                    MockLeader leader = new MockLeader(actorContext);
+                    // set the follower info in leader
+                    leader.addToFollowerToLog(followerActor.path().toString(), followersLastIndex, -1);
+
+                    // new entry
+                    ReplicatedLogImplEntry entry =
+                        new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
+                            new MockRaftActorContext.MockPayload("D"));
+
+
+                    RaftState raftState = leader.handleMessage(senderActor, new SendInstallSnapshot());
+
+                    assertEquals(RaftState.Leader, raftState);
+
+                    // 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
+                            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);
+                }
+            };
+        }};
+    }
+
+    @Test
+    public void testHandleInstallSnapshotReplyLastChunk() {
+        new LeaderTestKit(getSystem()) {{
+            new Within(duration("1 seconds")) {
+                protected void run() {
+                    ActorRef followerActor = getTestActor();
+
+                    Map<String, String> peerAddresses = new HashMap();
+                    peerAddresses.put(followerActor.path().toString(),
+                        followerActor.path().toString());
+
+                    MockRaftActorContext actorContext =
+                        (MockRaftActorContext) createActorContext();
+                    actorContext.setPeerAddresses(peerAddresses);
+
+                    final int followersLastIndex = 2;
+                    final int snapshotIndex = 3;
+                    final int newEntryIndex = 4;
+                    final int snapshotTerm = 1;
+                    final int currentTerm = 2;
+
+                    MockLeader leader = new MockLeader(actorContext);
+                    // set the follower info in leader
+                    leader.addToFollowerToLog(followerActor.path().toString(), followersLastIndex, -1);
+
+                    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().setSnapshot(
+                        toByteString(leadersSnapshot));
+                    actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
+                    actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
+                    actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
+
+                    ByteString bs = toByteString(leadersSnapshot);
+                    leader.createFollowerToSnapshot(followerActor.path().toString(), bs);
+                    while(!leader.getFollowerToSnapshot().isLastChunk(leader.getFollowerToSnapshot().getChunkIndex())) {
+                        leader.getFollowerToSnapshot().getNextChunk();
+                        leader.getFollowerToSnapshot().incrementChunkIndex();
+                    }
+
+                    //clears leaders log
+                    actorContext.getReplicatedLog().removeFrom(0);
 
+                    RaftState raftState = leader.handleMessage(senderActor,
+                        new InstallSnapshotReply(currentTerm, followerActor.path().toString(),
+                            leader.getFollowerToSnapshot().getChunkIndex(), true));
 
+                    assertEquals(RaftState.Leader, raftState);
+
+                    assertEquals(leader.mapFollowerToSnapshot.size(), 0);
+                    assertEquals(leader.followerToLog.size(), 1);
+                    assertNotNull(leader.followerToLog.get(followerActor.path().toString()));
+                    FollowerLogInformation fli = leader.followerToLog.get(followerActor.path().toString());
+                    assertEquals(snapshotIndex, fli.getMatchIndex().get());
+                    assertEquals(snapshotIndex, fli.getMatchIndex().get());
+                    assertEquals(snapshotIndex + 1, fli.getNextIndex().get());
+                }
             };
         }};
     }
 
+    @Test
+    public void testFollowerToSnapshotLogic() {
+
+        MockRaftActorContext actorContext = (MockRaftActorContext) createActorContext();
+
+        actorContext.setConfigParams(new DefaultConfigParamsImpl() {
+            @Override
+            public int getSnapshotChunkSize() {
+                return 50;
+            }
+        });
+
+        MockLeader leader = new MockLeader(actorContext);
+
+        Map<String, String> leadersSnapshot = new HashMap<>();
+        leadersSnapshot.put("1", "A");
+        leadersSnapshot.put("2", "B");
+        leadersSnapshot.put("3", "C");
+
+        ByteString bs = toByteString(leadersSnapshot);
+        byte[] barray = bs.toByteArray();
+
+        leader.createFollowerToSnapshot("followerId", bs);
+        assertEquals(bs.size(), barray.length);
+
+        int chunkIndex=0;
+        for (int i=0; i < barray.length; i = i + 50) {
+            int j = i + 50;
+            chunkIndex++;
+
+            if (i + 50 > barray.length) {
+                j = barray.length;
+            }
+
+            ByteString chunk = leader.getFollowerToSnapshot().getNextChunk();
+            assertEquals("bytestring size not matching for chunk:"+ chunkIndex, j-i, chunk.size());
+            assertEquals("chunkindex not matching", chunkIndex, leader.getFollowerToSnapshot().getChunkIndex());
+
+            leader.getFollowerToSnapshot().markSendStatus(true);
+            if (!leader.getFollowerToSnapshot().isLastChunk(chunkIndex)) {
+                leader.getFollowerToSnapshot().incrementChunkIndex();
+            }
+        }
+
+        assertEquals("totalChunks not matching", chunkIndex, leader.getFollowerToSnapshot().getTotalChunks());
+    }
+
+
     @Override protected RaftActorBehavior createBehavior(
         RaftActorContext actorContext) {
         return new Leader(actorContext);
     }
 
     @Override protected RaftActorContext createActorContext() {
-        return new MockRaftActorContext("test", getSystem(), leaderActor);
+        return createActorContext(leaderActor);
+    }
+
+    protected RaftActorContext createActorContext(ActorRef actorRef) {
+        return new MockRaftActorContext("test", getSystem(), actorRef);
+    }
+
+    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;
+    }
+
+    private static class LeaderTestKit extends JavaTestKit {
+
+        private LeaderTestKit(ActorSystem actorSystem) {
+            super(actorSystem);
+        }
+
+        protected void waitForLogMessage(final Class logLevel, ActorRef subject, String logMessage){
+            // Wait for a specific log message to show up
+            final boolean result =
+            new JavaTestKit.EventFilter<Boolean>(logLevel
+            ) {
+                @Override
+                protected Boolean run() {
+                    return true;
+                }
+            }.from(subject.path().toString())
+                .message(logMessage)
+                .occurrences(1).exec();
+
+            Assert.assertEquals(true, result);
+
+        }
+    }
+
+    class MockLeader extends Leader {
+
+        FollowerToSnapshot fts;
+
+        public MockLeader(RaftActorContext context){
+            super(context);
+        }
+
+        public void addToFollowerToLog(String followerId, long nextIndex, long matchIndex) {
+            FollowerLogInformation followerLogInformation =
+                new FollowerLogInformationImpl(followerId,
+                    new AtomicLong(nextIndex),
+                    new AtomicLong(matchIndex));
+            followerToLog.put(followerId, followerLogInformation);
+        }
+
+        public FollowerToSnapshot getFollowerToSnapshot() {
+            return fts;
+        }
+
+        public void createFollowerToSnapshot(String followerId, ByteString bs ) {
+            fts = new FollowerToSnapshot(bs);
+            mapFollowerToSnapshot.put(followerId, fts);
+
+        }
     }
 }
index 53f96e44f4105b8ecd3f2125be2360bd54a0b0c4..d4b1d84aa77c5d648291dba26025bad8511618a8 100644 (file)
@@ -145,6 +145,11 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         public void onDataChanged(final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
             bindingDataChangeListener.onDataChanged(new TranslatedDataChangeEvent(change, path));
         }
+
+        @Override
+        public String toString() {
+            return bindingDataChangeListener.getClass().getName();
+        }
     }
 
     private class TranslatedDataChangeEvent implements AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> {
index 2d8e51cff9d1a1c00e50a03aa671a9d97fce133e..d16170ba481d7d1a295a6acdcf33ae83b73b8a7d 100644 (file)
@@ -7,11 +7,10 @@
  */
 package org.opendaylight.controller.md.sal.binding.impl;
 
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import javax.annotation.concurrent.GuardedBy;
-
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
@@ -19,6 +18,7 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+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.DOMDataReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
@@ -26,20 +26,19 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.yangtools.concepts.Delegator;
 
-import com.google.common.base.Preconditions;
-
 class BindingTranslatedTransactionChain implements BindingTransactionChain, Delegator<DOMTransactionChain> {
 
     private final DOMTransactionChain delegate;
-
-    @GuardedBy("this")
-    private final Map<AsyncTransaction<?, ?>, AsyncTransaction<?, ?>> delegateTxToBindingTx = new WeakHashMap<>();
     private final BindingToNormalizedNodeCodec codec;
+    private final DelegateChainListener delegatingListener;
+    private final TransactionChainListener listener;
 
     public BindingTranslatedTransactionChain(final DOMDataBroker chainFactory,
             final BindingToNormalizedNodeCodec codec, final TransactionChainListener listener) {
         Preconditions.checkNotNull(chainFactory, "DOM Transaction chain factory must not be null");
-        this.delegate = chainFactory.createTransactionChain(new ListenerInvoker(listener));
+        this.delegatingListener = new DelegateChainListener();
+        this.listener = listener;
+        this.delegate = chainFactory.createTransactionChain(listener);
         this.codec = codec;
     }
 
@@ -52,56 +51,79 @@ class BindingTranslatedTransactionChain implements BindingTransactionChain, Dele
     public ReadOnlyTransaction newReadOnlyTransaction() {
         DOMDataReadOnlyTransaction delegateTx = delegate.newReadOnlyTransaction();
         ReadOnlyTransaction bindingTx = new BindingDataReadTransactionImpl(delegateTx, codec);
-        putDelegateToBinding(delegateTx, bindingTx);
         return bindingTx;
     }
 
     @Override
     public ReadWriteTransaction newReadWriteTransaction() {
         DOMDataReadWriteTransaction delegateTx = delegate.newReadWriteTransaction();
-        ReadWriteTransaction bindingTx = new BindingDataReadWriteTransactionImpl(delegateTx, codec);
-        putDelegateToBinding(delegateTx, bindingTx);
+        ReadWriteTransaction bindingTx = new BindingDataReadWriteTransactionImpl(delegateTx, codec) {
+
+            @Override
+            public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+                return listenForFailure(this,super.submit());
+            }
+
+        };
         return bindingTx;
     }
 
     @Override
     public WriteTransaction newWriteOnlyTransaction() {
-        DOMDataWriteTransaction delegateTx = delegate.newWriteOnlyTransaction();
-        WriteTransaction bindingTx = new BindingDataWriteTransactionImpl<>(delegateTx, codec);
-        putDelegateToBinding(delegateTx, bindingTx);
+        final DOMDataWriteTransaction delegateTx = delegate.newWriteOnlyTransaction();
+        WriteTransaction bindingTx = new BindingDataWriteTransactionImpl<DOMDataWriteTransaction>(delegateTx, codec) {
+
+            @Override
+            public CheckedFuture<Void,TransactionCommitFailedException> submit() {
+                return listenForFailure(this,super.submit());
+            };
+
+        };
         return bindingTx;
     }
 
-    @Override
-    public void close() {
-        delegate.close();
+    protected CheckedFuture<Void, TransactionCommitFailedException> listenForFailure(
+            final WriteTransaction tx, CheckedFuture<Void, TransactionCommitFailedException> future) {
+        Futures.addCallback(future, new FutureCallback<Void>() {
+            @Override
+            public void onFailure(Throwable t) {
+                failTransactionChain(tx,t);
+            }
+
+            @Override
+            public void onSuccess(Void result) {
+                // Intentionally NOOP
+            }
+        });
+
+        return future;
     }
 
-    private synchronized void putDelegateToBinding(final AsyncTransaction<?, ?> domTx,
-            final AsyncTransaction<?, ?> bindingTx) {
-        final Object previous = delegateTxToBindingTx.put(domTx, bindingTx);
-        Preconditions.checkState(previous == null, "DOM Transaction %s has already associated binding transation %s",domTx,previous);
+    protected void failTransactionChain(WriteTransaction tx, Throwable t) {
+        // We asume correct state change for underlaying transaction
+        // chain, so we are not changing any of our internal state
+        // to mark that we failed.
+        this.delegatingListener.onTransactionChainFailed(this, tx, t);
     }
 
-    private synchronized AsyncTransaction<?, ?> getBindingTransaction(final AsyncTransaction<?, ?> transaction) {
-        return delegateTxToBindingTx.get(transaction);
+    @Override
+    public void close() {
+        delegate.close();
     }
 
-    private final class ListenerInvoker implements TransactionChainListener {
-
-        private final TransactionChainListener listener;
-
-        public ListenerInvoker(final TransactionChainListener listener) {
-            this.listener = Preconditions.checkNotNull(listener, "Listener must not be null.");
-        }
+    private final class DelegateChainListener implements TransactionChainListener {
 
         @Override
         public void onTransactionChainFailed(final TransactionChain<?, ?> chain,
                 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
-            Preconditions.checkState(delegate.equals(chain),
-                    "Illegal state - listener for %s was invoked for incorrect chain %s.", delegate, chain);
-            AsyncTransaction<?, ?> bindingTx = getBindingTransaction(transaction);
-            listener.onTransactionChainFailed(chain, bindingTx, cause);
+            /*
+             * Intentionally NOOP, callback for failure, since we
+             * are also listening on each transaction for failure.
+             *
+             * by listening on submit future for Binding transaction
+             * in order to provide Binding transaction (which was seen by client
+             * of this transaction chain, instead of
+            */
         }
 
         @Override
index ab6d56c15a5bdb696f5cb136965519206f40ef79..6be5f2d481515c1dd0b6fb140ff63fdf2e9d019b 100644 (file)
@@ -3,6 +3,12 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
 import java.lang.ref.WeakReference;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
@@ -21,13 +27,13 @@ import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
-import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -35,12 +41,6 @@ import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMapping
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Function;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
 class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
 
     private final Logger LOG = LoggerFactory.getLogger(DomToBindingRpcForwarder.class);
@@ -65,8 +65,8 @@ class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
     static {
         try {
             EQUALS_METHOD = Object.class.getMethod("equals", Object.class);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw new ExceptionInInitializerError(e);
         }
     }
 
@@ -94,7 +94,7 @@ class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
     }
 
     /**
-     * Constructor for Routed RPC Forwareder.
+     * Constructor for Routed RPC Forwarder.
      *
      * @param service
      * @param context
index dba2908e9c4a9309bf3a1acba4e4fcc5974f7a03..efd35ccfa606d298834cb0eaa05a4d5d393a825a 100644 (file)
@@ -100,6 +100,7 @@ public class TestHelper {
                 mavenBundle("org.javassist", "javassist").versionAsInProject(), // //
 
                 mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), // //
+                mavenBundle(YANGTOOLS, "yang-data-util").versionAsInProject(), // //
                 mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), // //
                 mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), // //
                 mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), // //
index 2bf1a5597362c9eeee9a312ea179dda1a093815f..a3619ec4d230463edcbf7e15957b230db9d0cb09 100644 (file)
           <artifactId>jsr305</artifactId>
           <version>2.0.1</version>
       </dependency>
-
       <dependency>
           <groupId>com.codahale.metrics</groupId>
           <artifactId>metrics-core</artifactId>
-          <version>3.0.1</version>
+      </dependency>
+      <dependency>
+          <groupId>com.codahale.metrics</groupId>
+          <artifactId>metrics-graphite</artifactId>
       </dependency>
   </dependencies>
   <build>
+
       <plugins>
           <plugin>
               <groupId>org.jacoco</groupId>
                   </execution>
               </executions>
           </plugin>
-      </plugins>
+          <plugin>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>maven-bundle-plugin</artifactId>
+            <extensions>true</extensions>
+            <configuration>
+            <instructions>
+                <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                <Export-Package>org.opendaylight.controller.cluster.*,org.opendaylight.common.actor,org.opendaylight.common.reporting,org.opendaylight.controller.protobuff.*,org.opendaylight.controller.xml.*</Export-Package>
+                <Import-Package>*</Import-Package>
+            </instructions>
+            </configuration>
+          </plugin>
+    </plugins>
   </build>
-
 </project>
index 646431522e3c9d4ee3b7b3703839505b38f39bfd..c6d3625ac3ca4ba2cb5e093a64a8681e5c1b4b81 100644 (file)
@@ -11,9 +11,8 @@ package org.opendaylight.controller.common.actor;
 import akka.actor.ActorPath;
 import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
-import akka.dispatch.BoundedMailbox;
+import akka.dispatch.BoundedDequeBasedMailbox;
 import akka.dispatch.MailboxType;
-import akka.dispatch.MessageQueue;
 import akka.dispatch.ProducesMessageQueue;
 import com.codahale.metrics.Gauge;
 import com.codahale.metrics.MetricRegistry;
@@ -24,7 +23,7 @@ import scala.concurrent.duration.FiniteDuration;
 
 import java.util.concurrent.TimeUnit;
 
-public class MeteredBoundedMailbox implements MailboxType, ProducesMessageQueue<BoundedMailbox.MessageQueue> {
+public class MeteredBoundedMailbox implements MailboxType, ProducesMessageQueue<MeteredBoundedMailbox.MeteredMessageQueue> {
 
     private MeteredMessageQueue queue;
     private Integer capacity;
@@ -33,16 +32,18 @@ public class MeteredBoundedMailbox implements MailboxType, ProducesMessageQueue<
     private MetricsReporter reporter;
 
     private final String QUEUE_SIZE = "queue-size";
+    private final String CAPACITY = "mailbox-capacity";
+    private final String TIMEOUT  = "mailbox-push-timeout-time";
     private final Long DEFAULT_TIMEOUT = 10L;
 
     public MeteredBoundedMailbox(ActorSystem.Settings settings, Config config) {
         Preconditions.checkArgument( config.hasPath("mailbox-capacity"), "Missing configuration [mailbox-capacity]" );
-        this.capacity = config.getInt("mailbox-capacity");
+        this.capacity = config.getInt(CAPACITY);
         Preconditions.checkArgument( this.capacity > 0, "mailbox-capacity must be > 0");
 
         Long timeout = -1L;
-        if ( config.hasPath("mailbox-push-timeout-time") ){
-            timeout = config.getDuration("mailbox-push-timeout-time", TimeUnit.NANOSECONDS);
+        if ( config.hasPath(TIMEOUT) ){
+            timeout = config.getDuration(TIMEOUT, TimeUnit.NANOSECONDS);
         } else {
             timeout = DEFAULT_TIMEOUT;
         }
@@ -54,7 +55,7 @@ public class MeteredBoundedMailbox implements MailboxType, ProducesMessageQueue<
 
 
     @Override
-    public MessageQueue create(final scala.Option<ActorRef> owner, scala.Option<ActorSystem> system) {
+    public MeteredMessageQueue create(final scala.Option<ActorRef> owner, scala.Option<ActorSystem> system) {
         this.queue = new MeteredMessageQueue(this.capacity, this.pushTimeOut);
         monitorQueueSize(owner, this.queue);
         return this.queue;
@@ -65,14 +66,15 @@ public class MeteredBoundedMailbox implements MailboxType, ProducesMessageQueue<
             return; //there's no actor to monitor
         }
         actorPath = owner.get().path();
-        MetricRegistry registry = reporter.getMetricsRegistry();
+        String actorInstanceId = Integer.toString(owner.get().hashCode());
 
-        String actorName = registry.name(actorPath.toString(), QUEUE_SIZE);
+        MetricRegistry registry = reporter.getMetricsRegistry();
+        String actorName = registry.name(actorPath.toString(), actorInstanceId, QUEUE_SIZE);
 
         if (registry.getMetrics().containsKey(actorName))
             return; //already registered
 
-        reporter.getMetricsRegistry().register(actorName,
+        registry.register(actorName,
                 new Gauge<Integer>() {
                     @Override
                     public Integer getValue() {
@@ -82,7 +84,7 @@ public class MeteredBoundedMailbox implements MailboxType, ProducesMessageQueue<
     }
 
 
-    public static class MeteredMessageQueue extends BoundedMailbox.MessageQueue {
+    public static class MeteredMessageQueue extends BoundedDequeBasedMailbox.MessageQueue {
 
         public MeteredMessageQueue(int capacity, FiniteDuration pushTimeOut) {
             super(capacity, pushTimeOut);
index 5848561676b34ff68b744afa4f5f76b2acd680ca..ea8f4a3ef19810a6d95ebc4211b0f4569b6e2716 100644 (file)
@@ -75,9 +75,13 @@ public class XmlUtils {
    */
   public static String inputCompositeNodeToXml(CompositeNode cNode, SchemaContext schemaContext){
     LOG.debug("Converting input composite node to xml {}", cNode);
-    if (cNode == null) return BLANK;
+    if (cNode == null) {
+        return BLANK;
+    }
 
-    if(schemaContext == null) return BLANK;
+    if(schemaContext == null) {
+        return BLANK;
+    }
 
     Document domTree = null;
     try {
@@ -108,9 +112,13 @@ public class XmlUtils {
    */
   public static String outputCompositeNodeToXml(CompositeNode cNode, SchemaContext schemaContext){
     LOG.debug("Converting output composite node to xml {}", cNode);
-    if (cNode == null) return BLANK;
+    if (cNode == null) {
+        return BLANK;
+    }
 
-    if(schemaContext == null) return BLANK;
+    if(schemaContext == null) {
+        return BLANK;
+    }
 
     Document domTree = null;
     try {
@@ -150,7 +158,9 @@ public class XmlUtils {
   }
 
   public static CompositeNode xmlToCompositeNode(String xml){
-    if (xml==null || xml.length()==0) return null;
+    if (xml==null || xml.length()==0) {
+        return null;
+    }
 
     Node<?> dataTree;
     try {
@@ -179,11 +189,17 @@ public class XmlUtils {
    */
   public static CompositeNode inputXmlToCompositeNode(QName rpc, String xml,  SchemaContext schemaContext){
     LOG.debug("Converting input xml to composite node {}", xml);
-    if (xml==null || xml.length()==0) return null;
+    if (xml==null || xml.length()==0) {
+        return null;
+    }
 
-    if(rpc == null) return null;
+    if(rpc == null) {
+        return null;
+    }
 
-    if(schemaContext == null) return null;
+    if(schemaContext == null) {
+        return null;
+    }
 
     CompositeNode compositeNode = null;
     try {
@@ -213,7 +229,7 @@ public class XmlUtils {
           LOG.debug("Converted xml input to list of nodes  {}", dataNodes);
 
           final CompositeNodeBuilder<ImmutableCompositeNode> it = ImmutableCompositeNode.builder();
-          it.setQName(input);
+          it.setQName(rpc);
           it.add(ImmutableCompositeNode.create(input, dataNodes));
           compositeNode = it.toInstance();
           break;
index 1e60803f05af52d965a3b927b2423bd22e023064..0f96c1002de540fa0071a4cb7d96710c591bfd23 100644 (file)
@@ -44,7 +44,8 @@ public class MeteredBoundedMailboxTest {
         actorSystem.eventStream().subscribe(mockReceiver.getRef(), DeadLetter.class);
 
 
-        final FiniteDuration TEN_SEC = new FiniteDuration(10, TimeUnit.SECONDS);
+        final FiniteDuration TWENTY_SEC = new FiniteDuration(20, TimeUnit.SECONDS);
+
         String boundedMailBox = actorSystem.name() + ".bounded-mailbox";
         ActorRef pingPongActor = actorSystem.actorOf(PingPongActor.props(lock).withMailbox(boundedMailBox),
                                                      "pingpongactor");
@@ -59,11 +60,11 @@ public class MeteredBoundedMailboxTest {
             pingPongActor.tell("ping", mockReceiver.getRef());
         }
 
-        mockReceiver.expectMsgClass(TEN_SEC, DeadLetter.class);
+        mockReceiver.expectMsgClass(TWENTY_SEC, DeadLetter.class);
 
         lock.unlock();
 
-        Object[] eleven = mockReceiver.receiveN(11, TEN_SEC);
+        Object[] eleven = mockReceiver.receiveN(11, TWENTY_SEC);
     }
 
     /**
@@ -89,8 +90,12 @@ public class MeteredBoundedMailboxTest {
         @Override
         public void onReceive(Object message) throws Exception {
             lock.lock();
-            if ("ping".equals(message))
-                getSender().tell("pong", getSelf());
+            try {
+                if ("ping".equals(message))
+                    getSender().tell("pong", getSelf());
+            } finally {
+                lock.unlock();
+            }
         }
     }
 }
\ No newline at end of file
index 31b658d1d7ea6f618f8277e4c5d214124d4613d6..91c0b5caa1ebd0854f44943164d9f9a89aec855d 100644 (file)
                   <type>xml</type>
                   <classifier>config</classifier>
                 </artifact>
+                <artifact>
+                  <file>${project.build.directory}/classes/initial/akka.conf</file>
+                  <type>xml</type>
+                  <classifier>akkaconf</classifier>
+                </artifact>
+                <artifact>
+                  <file>${project.build.directory}/classes/initial/module-shards.conf</file>
+                  <type>xml</type>
+                  <classifier>moduleshardconf</classifier>
+                </artifact>
+                <artifact>
+                  <file>${project.build.directory}/classes/initial/modules.conf</file>
+                  <type>xml</type>
+                  <classifier>moduleconf</classifier>
+                </artifact>
               </artifacts>
             </configuration>
           </execution>
index 0535179aadf79c4196a8f606433c1cd8b4e89949..5a2116b50f92070687736329e95441a246ed49b0 100644 (file)
@@ -1,5 +1,10 @@
 
 odl-cluster-data {
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 100ms
+  }    
   akka {
     actor {
       provider = "akka.cluster.ClusterActorRefProvider"
@@ -16,7 +21,7 @@ odl-cluster-data {
     remote {
       log-remote-lifecycle-events = off
       netty.tcp {
-        hostname = "<CHANGE_ME>"
+        hostname = "127.0.0.1"
         port = 2550
         maximum-frame-size = 419430400
         send-buffer-size = 52428800
@@ -25,14 +30,24 @@ odl-cluster-data {
     }
 
     cluster {
-      seed-nodes = ["akka.tcp://opendaylight-cluster-data@<CHANGE_SEED_IP>:2550"]
+      seed-nodes = ["akka.tcp://opendaylight-cluster-data@127.0.0.1:2550"]
 
       auto-down-unreachable-after = 10s
+
+      roles = [
+        "member-1"
+      ]
+
     }
   }
 }
 
 odl-cluster-rpc {
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 100ms
+  }
   akka {
     actor {
       provider = "akka.cluster.ClusterActorRefProvider"
@@ -41,13 +56,13 @@ odl-cluster-rpc {
     remote {
       log-remote-lifecycle-events = off
       netty.tcp {
-        hostname = "<CHANGE_ME>"
+        hostname = "127.0.0.1"
         port = 2551
       }
     }
 
     cluster {
-      seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@<CHANGE_SEED_IP>:2551"]
+      seed-nodes = ["akka.tcp://opendaylight-cluster-rpc@127.0.0.1:2551"]
 
       auto-down-unreachable-after = 10s
     }
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/AbstractMXBean.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/AbstractMXBean.java
new file mode 100644 (file)
index 0000000..a2db29d
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.common.util.jmx;
+
+import java.lang.management.ManagementFactory;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Abstract base for an MXBean implementation class.
+ * <p>
+ * This class is not intended for use outside of MD-SAL and its part of private
+ * implementation (still exported as public to be reused across MD-SAL implementation
+ * components) and may be removed in subsequent
+ * releases.
+ *
+ * @author Thomas Pantelis
+ */
+@Beta
+public abstract class AbstractMXBean {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractMXBean.class);
+
+    public static String BASE_JMX_PREFIX = "org.opendaylight.controller:";
+
+    private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+    private final String mBeanName;
+    private final String mBeanType;
+    private final String mBeanCategory;
+
+    /**
+     * Constructor.
+     *
+     * @param mBeanName Used as the <code>name</code> property in the bean's ObjectName.
+     * @param mBeanType Used as the <code>type</code> property in the bean's ObjectName.
+     * @param mBeanCategory Used as the <code>Category</code> property in the bean's ObjectName.
+     */
+    protected AbstractMXBean(@Nonnull String mBeanName, @Nonnull String mBeanType,
+            @Nullable String mBeanCategory) {
+        this.mBeanName = mBeanName;
+        this.mBeanType = mBeanType;
+        this.mBeanCategory = mBeanCategory;
+    }
+
+    private ObjectName getMBeanObjectName() throws MalformedObjectNameException {
+        StringBuilder builder = new StringBuilder(BASE_JMX_PREFIX)
+                .append("type=").append(getMBeanType());
+
+        if(getMBeanCategory() != null) {
+            builder.append(",Category=").append(getMBeanCategory());
+        }
+
+        builder.append(",name=").append(getMBeanName());
+        return new ObjectName(builder.toString());
+    }
+
+    /**
+     * Registers this bean with the platform MBean server with the domain defined by
+     * {@link #BASE_JMX_PREFIX}.
+     *
+     * @return true is successfully registered, false otherwise.
+     */
+    public boolean registerMBean() {
+        boolean registered = false;
+        try {
+            // Object to identify MBean
+            final ObjectName mbeanName = this.getMBeanObjectName();
+
+            LOG.debug("Register MBean {}", mbeanName);
+
+            // unregistered if already registered
+            if(server.isRegistered(mbeanName)) {
+
+                LOG.debug("MBean {} found to be already registered", mbeanName);
+
+                try {
+                    unregisterMBean(mbeanName);
+                } catch(Exception e) {
+
+                    LOG.warn("unregister mbean {} resulted in exception {} ", mbeanName, e);
+                }
+            }
+            server.registerMBean(this, mbeanName);
+            registered = true;
+
+            LOG.debug("MBean {} registered successfully", mbeanName.getCanonicalName());
+        } catch(Exception e) {
+
+            LOG.error("registration failed {}", e);
+
+        }
+        return registered;
+    }
+
+    /**
+     * Unregisters this bean with the platform MBean server.
+     *
+     * @return true is successfully unregistered, false otherwise.
+     */
+    public boolean unregisterMBean() {
+        boolean unregister = false;
+        try {
+            ObjectName mbeanName = this.getMBeanObjectName();
+            unregisterMBean(mbeanName);
+            unregister = true;
+        } catch(Exception e) {
+
+            LOG.error("Failed when unregistering MBean {}", e);
+        }
+
+        return unregister;
+    }
+
+    private void unregisterMBean(ObjectName mbeanName) throws MBeanRegistrationException,
+            InstanceNotFoundException {
+        server.unregisterMBean(mbeanName);
+    }
+
+    /**
+     * Returns the <code>name</code> property of the bean's ObjectName.
+     */
+    public String getMBeanName() {
+        return mBeanName;
+    }
+
+    /**
+     * Returns the <code>type</code> property of the bean's ObjectName.
+     */
+    public String getMBeanType() {
+        return mBeanType;
+    }
+
+    /**
+     * Returns the <code>Category</code> property of the bean's ObjectName.
+     */
+    public String getMBeanCategory() {
+        return mBeanCategory;
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBean.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBean.java
new file mode 100644 (file)
index 0000000..9646adc
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.common.util.jmx;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.util.concurrent.ListenerNotificationQueueStats;
+
+/**
+ * MXBean interface for {@link QueuedNotificationManager} statistic metrics.
+ *
+ * @author Thomas Pantelis
+ */
+public interface QueuedNotificationManagerMXBean {
+
+    /**
+     * Returns a list of stat instances for each current listener notification task in progress.
+     */
+    List<ListenerNotificationQueueStats> getCurrentListenerQueueStats();
+
+    /**
+     * Returns the configured maximum listener queue size.
+     */
+    int getMaxListenerQueueSize();
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBeanImpl.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerMXBeanImpl.java
new file mode 100644 (file)
index 0000000..e6148fc
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.common.util.jmx;
+
+import java.util.List;
+
+import org.opendaylight.yangtools.util.concurrent.ListenerNotificationQueueStats;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Implementation of the QueuedNotificationManagerMXBean interface.
+ *
+ * <p>
+ * This class is not intended for use outside of MD-SAL and its part of private
+ * implementation (still exported as public to be reused across MD-SAL implementation
+ * components) and may be removed in subsequent
+ * releases.
+ *
+ * @author Thomas Pantelis
+ */
+public class QueuedNotificationManagerMXBeanImpl extends AbstractMXBean
+                                                 implements QueuedNotificationManagerMXBean {
+
+    private final QueuedNotificationManager<?,?> manager;
+
+    public QueuedNotificationManagerMXBeanImpl( QueuedNotificationManager<?,?> manager,
+            String mBeanName, String mBeanType, String mBeanCategory ) {
+        super(mBeanName, mBeanType, mBeanCategory);
+        this.manager = Preconditions.checkNotNull( manager );
+    }
+
+    @Override
+    public List<ListenerNotificationQueueStats> getCurrentListenerQueueStats() {
+        return manager.getListenerNotificationQueueStats();
+    }
+
+    @Override
+    public int getMaxListenerQueueSize() {
+        return manager.getMaxQueueCapacity();
+    }
+
+    public QueuedNotificationManagerStats toQueuedNotificationManagerStats() {
+        return new QueuedNotificationManagerStats( getMaxListenerQueueSize(),
+                getCurrentListenerQueueStats() );
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerStats.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/QueuedNotificationManagerStats.java
new file mode 100644 (file)
index 0000000..c6e5006
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.common.util.jmx;
+
+import java.beans.ConstructorProperties;
+import java.util.List;
+
+import org.opendaylight.yangtools.util.concurrent.ListenerNotificationQueueStats;
+
+/**
+ * A bean class that holds various QueuedNotificationManager statistic metrics. This class is
+ * suitable for mapping to the MXBean CompositeDataSupport type.
+ *
+ * <p>
+ * This class is not intended for use outside of MD-SAL and its part of private
+ * implementation (still exported as public to be reused across MD-SAL implementation
+ * components) and may be removed in subsequent
+ * releases.
+ * @author Thomas Pantelis
+ * @see QueuedNotificationManagerMXBeanImpl
+ */
+public class QueuedNotificationManagerStats {
+
+    private final int maxListenerQueueSize;
+    private final List<ListenerNotificationQueueStats> currentListenerQueueStats;
+
+    @ConstructorProperties({"maxListenerQueueSize","currentListenerQueueStats"})
+    public QueuedNotificationManagerStats( int maxListenerQueueSize,
+            List<ListenerNotificationQueueStats> currentListenerQueueStats ) {
+        super();
+        this.maxListenerQueueSize = maxListenerQueueSize;
+        this.currentListenerQueueStats = currentListenerQueueStats;
+    }
+
+    public List<ListenerNotificationQueueStats> getCurrentListenerQueueStats() {
+        return currentListenerQueueStats;
+    }
+
+    public int getMaxListenerQueueSize() {
+        return maxListenerQueueSize;
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStats.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStats.java
new file mode 100644 (file)
index 0000000..0a766c0
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.common.util.jmx;
+
+import java.beans.ConstructorProperties;
+
+/**
+ * A bean class that holds various thread executor statistic metrics. This class is suitable for
+ * mapping to the MXBean CompositeDataSupport type;
+ *
+ * @author Thomas Pantelis
+ * @see ThreadExecutorStatsMXBeanImpl
+ */
+public class ThreadExecutorStats {
+
+    private final long activeThreadCount;
+    private final long completedTaskCount;
+    private final long currentQueueSize;
+    private final long maxThreadPoolSize;
+    private final long totalTaskCount;
+    private final long largestThreadPoolSize;
+    private final long maxQueueSize;
+    private final long currentThreadPoolSize;
+
+    // The following fields are defined as Long because they may be null if we can't a value
+    // from the underlying executor.
+    private final Long largestQueueSize;
+    private final Long rejectedTaskCount;
+
+    @ConstructorProperties({"activeThreadCount","currentThreadPoolSize","largestThreadPoolSize",
+        "maxThreadPoolSize","currentQueueSize","largestQueueSize","maxQueueSize",
+        "completedTaskCount","totalTaskCount","rejectedTaskCount"})
+    public ThreadExecutorStats(long activeThreadCount, long currentThreadPoolSize,
+            long largestThreadPoolSize, long maxThreadPoolSize, long currentQueueSize,
+            Long largestQueueSize, long maxQueueSize, long completedTaskCount,
+            long totalTaskCount, Long rejectedTaskCount) {
+        this.activeThreadCount = activeThreadCount;
+        this.currentThreadPoolSize = currentThreadPoolSize;
+        this.largestQueueSize = largestQueueSize;
+        this.largestThreadPoolSize = largestThreadPoolSize;
+        this.maxThreadPoolSize = maxThreadPoolSize;
+        this.currentQueueSize = currentQueueSize;
+        this.maxQueueSize = maxQueueSize;
+        this.completedTaskCount = completedTaskCount;
+        this.totalTaskCount = totalTaskCount;
+        this.rejectedTaskCount = rejectedTaskCount;
+    }
+
+    public long getActiveThreadCount() {
+        return activeThreadCount;
+    }
+
+    public long getCompletedTaskCount() {
+        return completedTaskCount;
+    }
+
+    public Long getRejectedTaskCount() {
+        return rejectedTaskCount;
+    }
+
+    public long getCurrentQueueSize() {
+        return currentQueueSize;
+    }
+
+    public Long getLargestQueueSize() {
+        return largestQueueSize;
+    }
+
+    public long getMaxThreadPoolSize() {
+        return maxThreadPoolSize;
+    }
+
+    public long getTotalTaskCount() {
+        return totalTaskCount;
+    }
+
+    public long getLargestThreadPoolSize() {
+        return largestThreadPoolSize;
+    }
+
+    public long getMaxQueueSize() {
+        return maxQueueSize;
+    }
+
+    public long getCurrentThreadPoolSize() {
+        return currentThreadPoolSize;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBean.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBean.java
new file mode 100644 (file)
index 0000000..d30bf88
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.common.util.jmx;
+
+/**
+ * MXBean interface for thread executor statistic metrics.
+ *
+ * @author Thomas Pantelis
+ */
+public interface ThreadExecutorStatsMXBean {
+
+    /**
+     * Returns the current thread pool size.
+     */
+    long getCurrentThreadPoolSize();
+
+    /**
+     * Returns the largest thread pool size.
+     */
+    long getLargestThreadPoolSize();
+
+    /**
+     * Returns the maximum thread pool size.
+     */
+    long getMaxThreadPoolSize();
+
+    /**
+     * Returns the current queue size.
+     */
+    long getCurrentQueueSize();
+
+    /**
+     * Returns the largest queue size, if available.
+     */
+    Long getLargestQueueSize();
+
+    /**
+     * Returns the maximum queue size.
+     */
+    long getMaxQueueSize();
+
+    /**
+     * Returns the active thread count.
+     */
+    long getActiveThreadCount();
+
+    /**
+     * Returns the completed task count.
+     */
+    long getCompletedTaskCount();
+
+    /**
+     * Returns the total task count.
+     */
+    long getTotalTaskCount();
+
+    /**
+     * Returns the rejected task count, if available.
+     */
+    Long getRejectedTaskCount();
+}
diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/md/sal/common/util/jmx/ThreadExecutorStatsMXBeanImpl.java
new file mode 100644 (file)
index 0000000..b67855d
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.common.util.jmx;
+
+import com.google.common.base.Preconditions;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadPoolExecutor;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.util.concurrent.CountingRejectedExecutionHandler;
+import org.opendaylight.yangtools.util.concurrent.TrackingLinkedBlockingQueue;
+
+/**
+ * MXBean implementation of the ThreadExecutorStatsMXBean interface that retrieves statistics
+ * from a backing {@link java.util.concurrent.ExecutorService}.
+ *
+ * @author Thomas Pantelis
+ */
+public class ThreadExecutorStatsMXBeanImpl extends AbstractMXBean
+                                           implements ThreadExecutorStatsMXBean {
+
+    private final ThreadPoolExecutor executor;
+
+    /**
+     * Constructs an instance for the given {@link Executor}.
+     *
+     * @param executor the backing {@link Executor}
+     * @param mBeanName Used as the <code>name</code> property in the bean's ObjectName.
+     * @param mBeanType Used as the <code>type</code> property in the bean's ObjectName.
+     * @param mBeanCategory Used as the <code>Category</code> property in the bean's ObjectName.
+     */
+    public ThreadExecutorStatsMXBeanImpl(Executor executor, String mBeanName,
+            String mBeanType, @Nullable String mBeanCategory) {
+        super(mBeanName, mBeanType, mBeanCategory);
+
+        Preconditions.checkArgument(executor instanceof ThreadPoolExecutor,
+                "The ExecutorService of type {} is not an instanceof ThreadPoolExecutor",
+                executor.getClass());
+        this.executor = (ThreadPoolExecutor)executor;
+    }
+
+    @Override
+    public long getCurrentThreadPoolSize() {
+        return executor.getPoolSize();
+    }
+
+    @Override
+    public long getLargestThreadPoolSize() {
+        return  executor.getLargestPoolSize();
+    }
+
+    @Override
+    public long getMaxThreadPoolSize() {
+        return executor.getMaximumPoolSize();
+    }
+
+    @Override
+    public long getCurrentQueueSize() {
+        return executor.getQueue().size();
+    }
+
+    @Override
+    public Long getLargestQueueSize() {
+        BlockingQueue<Runnable> queue = executor.getQueue();
+        if(queue instanceof TrackingLinkedBlockingQueue) {
+            return Long.valueOf(((TrackingLinkedBlockingQueue<?>)queue).getLargestQueueSize());
+        }
+
+        return null;
+    }
+
+    @Override
+    public long getMaxQueueSize() {
+        long queueSize = executor.getQueue().size();
+        return executor.getQueue().remainingCapacity() + queueSize;
+    }
+
+    @Override
+    public long getActiveThreadCount() {
+        return executor.getActiveCount();
+    }
+
+    @Override
+    public long getCompletedTaskCount() {
+        return  executor.getCompletedTaskCount();
+    }
+
+    @Override
+    public long getTotalTaskCount() {
+        return executor.getTaskCount();
+    }
+
+    @Override
+    public Long getRejectedTaskCount() {
+        RejectedExecutionHandler rejectedHandler = executor.getRejectedExecutionHandler();
+        if(rejectedHandler instanceof CountingRejectedExecutionHandler) {
+            return Long.valueOf(((CountingRejectedExecutionHandler)rejectedHandler)
+                                                                     .getRejectedTaskCount());
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a {@link ThreadExecutorStats} instance containing a snapshot of the statistic
+     * metrics.
+     */
+    public ThreadExecutorStats toThreadExecutorStats() {
+        return new ThreadExecutorStats(getActiveThreadCount(), getCurrentThreadPoolSize(),
+                getLargestThreadPoolSize(), getMaxThreadPoolSize(), getCurrentQueueSize(),
+                getLargestQueueSize(), getMaxQueueSize(), getCompletedTaskCount(),
+                getTotalTaskCount(), getRejectedTaskCount());
+    }
+}
index 4669fbdb61ec7a28c67af91cb9157cfbaa81965b..82998226b68e3049093a8be77f96227824db123e 100644 (file)
       <artifactId>akka-slf4j_${scala.version}</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-osgi_${scala.version}</artifactId>
+    </dependency>
+
     <!-- SAL Dependencies -->
 
     <dependency>
       <dependency>
           <groupId>com.codahale.metrics</groupId>
           <artifactId>metrics-core</artifactId>
-          <version>3.0.1</version>
+      </dependency>
+
+      <dependency>
+          <groupId>com.codahale.metrics</groupId>
+          <artifactId>metrics-graphite</artifactId>
       </dependency>
     <!-- Test Dependencies -->
     <dependency>
             <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
             <Export-package></Export-package>
             <Private-Package></Private-Package>
-            <Import-Package>!*snappy;!org.jboss.*;!com.jcraft.*;*</Import-Package>
+            <Import-Package>!*snappy;!org.jboss.*;!com.jcraft.*;!*jetty*;!sun.security.*;*</Import-Package>
+            <!--
             <Embed-Dependency>
                 sal-clustering-commons;
                 sal-akka-raft;
                 *scala*;
             </Embed-Dependency>
             <Embed-Transitive>true</Embed-Transitive>
+            -->
           </instructions>
         </configuration>
       </plugin>
index 15c0548761ecd96afee865025fc573d5a2d38c6e..b326d61fc62211f00d03d636ed635f7e959cf09d 100644 (file)
@@ -10,24 +10,55 @@ package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorSystem;
 import akka.actor.Props;
-import com.google.common.base.Function;
+import akka.osgi.BundleDelegatingClassLoader;
+import com.google.common.base.Preconditions;
+import com.typesafe.config.Config;
 import com.typesafe.config.ConfigFactory;
+import org.osgi.framework.BundleContext;
 
-import javax.annotation.Nullable;
+import java.io.File;
 
 public class ActorSystemFactory {
-    private static final ActorSystem actorSystem = (new Function<Void, ActorSystem>(){
-
-        @Nullable @Override public ActorSystem apply(@Nullable Void aVoid) {
-                ActorSystem system =
-                    ActorSystem.create("opendaylight-cluster-data", ConfigFactory
-                        .load().getConfig("odl-cluster-data"));
-                system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor");
-                return system;
-        }
-    }).apply(null);
+
+    public static final String AKKA_CONF_PATH = "./configuration/initial/akka.conf";
+    public static final String ACTOR_SYSTEM_NAME = "opendaylight-cluster-data";
+    public static final String CONFIGURATION_NAME = "odl-cluster-data";
+
+    private static volatile ActorSystem actorSystem = null;
 
     public static final ActorSystem getInstance(){
         return actorSystem;
     }
+
+    /**
+     * This method should be called only once during initialization
+     *
+     * @param bundleContext
+     */
+    public static final ActorSystem createInstance(final BundleContext bundleContext) {
+        if(actorSystem == null) {
+            // Create an OSGi bundle classloader for actor system
+            BundleDelegatingClassLoader classLoader = new BundleDelegatingClassLoader(bundleContext.getBundle(),
+                Thread.currentThread().getContextClassLoader());
+            synchronized (ActorSystemFactory.class) {
+                // Double check
+
+                if (actorSystem == null) {
+                    ActorSystem system = ActorSystem.create(ACTOR_SYSTEM_NAME,
+                        ConfigFactory.load(readAkkaConfiguration()).getConfig(CONFIGURATION_NAME), classLoader);
+                    system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor");
+                    actorSystem = system;
+                }
+            }
+        }
+
+        return actorSystem;
+    }
+
+
+    private static final Config readAkkaConfiguration(){
+        File defaultConfigFile = new File(AKKA_CONF_PATH);
+        Preconditions.checkState(defaultConfigFile.exists(), "akka.conf is missing");
+        return ConfigFactory.parseFile(defaultConfigFile);
+    }
 }
@@ -8,30 +8,29 @@
 
 package org.opendaylight.controller.cluster.datastore;
 
-import java.util.concurrent.TimeUnit;
-
-import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
 import com.google.common.base.Preconditions;
-
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
 import scala.concurrent.duration.Duration;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Contains contextual data for shards.
  *
  * @author Thomas Pantelis
  */
-public class ShardContext {
+public class DatastoreContext {
 
     private final InMemoryDOMDataStoreConfigProperties dataStoreProperties;
     private final Duration shardTransactionIdleTimeout;
 
-    public ShardContext() {
+    public DatastoreContext() {
         this.dataStoreProperties = null;
         this.shardTransactionIdleTimeout = Duration.create(10, TimeUnit.MINUTES);
     }
 
-    public ShardContext(InMemoryDOMDataStoreConfigProperties dataStoreProperties,
-            Duration shardTransactionIdleTimeout) {
+    public DatastoreContext(InMemoryDOMDataStoreConfigProperties dataStoreProperties,
+        Duration shardTransactionIdleTimeout) {
         this.dataStoreProperties = Preconditions.checkNotNull(dataStoreProperties);
         this.shardTransactionIdleTimeout = Preconditions.checkNotNull(shardTransactionIdleTimeout);
     }
@@ -43,4 +42,6 @@ public class ShardContext {
     public Duration getShardTransactionIdleTimeout() {
         return shardTransactionIdleTimeout;
     }
+
+
 }
index 51f3735f81ee6a9f4a5ad192cb6d1f1c27ebd031..0a137e07df43a1bb7ca2fb3e854d7f63adfd46a3 100644 (file)
@@ -46,7 +46,7 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au
     private static final Logger LOG = LoggerFactory.getLogger(DistributedDataStore.class);
 
     private final ActorContext actorContext;
-    private final ShardContext shardContext;
+    private final DatastoreContext datastoreContext;
 
     public DistributedDataStore(ActorSystem actorSystem, String type, ClusterWrapper cluster,
             Configuration configuration, DistributedDataStoreProperties dataStoreProperties) {
@@ -60,21 +60,25 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au
 
         LOG.info("Creating ShardManager : {}", shardManagerId);
 
-        shardContext = new ShardContext(InMemoryDOMDataStoreConfigProperties.create(
+        datastoreContext = new DatastoreContext(InMemoryDOMDataStoreConfigProperties.create(
                 dataStoreProperties.getMaxShardDataChangeExecutorPoolSize(),
                 dataStoreProperties.getMaxShardDataChangeExecutorQueueSize(),
                 dataStoreProperties.getMaxShardDataChangeListenerQueueSize()),
                 Duration.create(dataStoreProperties.getShardTransactionIdleTimeoutInMinutes(),
                         TimeUnit.MINUTES));
 
-        actorContext = new ActorContext(actorSystem, actorSystem
-            .actorOf(ShardManager.props(type, cluster, configuration, shardContext),
-                shardManagerId ), cluster, configuration);
+        actorContext
+                = new ActorContext(
+                    actorSystem, actorSystem.actorOf(
+                        ShardManager.props(type, cluster, configuration, datastoreContext).
+                            withMailbox(ActorContext.MAILBOX), shardManagerId ), cluster, configuration);
+
+        actorContext.setOperationTimeout(dataStoreProperties.getOperationTimeoutInSeconds());
     }
 
     public DistributedDataStore(ActorContext actorContext) {
         this.actorContext = Preconditions.checkNotNull(actorContext, "actorContext should not be null");
-        this.shardContext = new ShardContext();
+        this.datastoreContext = new DatastoreContext();
     }
 
 
@@ -96,8 +100,7 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au
         String shardName = ShardStrategyFactory.getStrategy(path).findShard(path);
 
         Object result = actorContext.executeLocalShardOperation(shardName,
-            new RegisterChangeListener(path, dataChangeListenerActor.path(), scope),
-            ActorContext.ASK_DURATION);
+            new RegisterChangeListener(path, dataChangeListenerActor.path(), scope));
 
         if (result != null) {
             RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result;
index 65a39a60e6c0819fe7f14543c268997a53fddff0..72b593f0106676a28bd251837f2566600d9359f1 100644 (file)
@@ -12,12 +12,13 @@ import akka.actor.ActorSystem;
 
 import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.osgi.framework.BundleContext;
 
 public class DistributedDataStoreFactory {
     public static DistributedDataStore createInstance(String name, SchemaService schemaService,
-            DistributedDataStoreProperties dataStoreProperties) {
+            DistributedDataStoreProperties dataStoreProperties, BundleContext bundleContext) {
 
-        ActorSystem actorSystem = ActorSystemFactory.getInstance();
+        ActorSystem actorSystem = ActorSystemFactory.createInstance(bundleContext);
         Configuration config = new ConfigurationImpl("module-shards.conf", "modules.conf");
         final DistributedDataStore dataStore =
             new DistributedDataStore(actorSystem, name, new ClusterWrapperImpl(actorSystem),
index eb6a5361381942306a9be7869d1048801f7c9a0f..df3245ffb225d9d3b0baf704e81e499ebdced314 100644 (file)
@@ -18,21 +18,24 @@ public class DistributedDataStoreProperties {
     private final int maxShardDataChangeExecutorQueueSize;
     private final int maxShardDataChangeExecutorPoolSize;
     private final int shardTransactionIdleTimeoutInMinutes;
+    private final int operationTimeoutInSeconds;
 
     public DistributedDataStoreProperties() {
         maxShardDataChangeListenerQueueSize = 1000;
         maxShardDataChangeExecutorQueueSize = 1000;
         maxShardDataChangeExecutorPoolSize = 20;
         shardTransactionIdleTimeoutInMinutes = 10;
+        operationTimeoutInSeconds = 5;
     }
 
     public DistributedDataStoreProperties(int maxShardDataChangeListenerQueueSize,
             int maxShardDataChangeExecutorQueueSize, int maxShardDataChangeExecutorPoolSize,
-            int shardTransactionIdleTimeoutInMinutes) {
+            int shardTransactionIdleTimeoutInMinutes, int operationTimeoutInSeconds) {
         this.maxShardDataChangeListenerQueueSize = maxShardDataChangeListenerQueueSize;
         this.maxShardDataChangeExecutorQueueSize = maxShardDataChangeExecutorQueueSize;
         this.maxShardDataChangeExecutorPoolSize = maxShardDataChangeExecutorPoolSize;
         this.shardTransactionIdleTimeoutInMinutes = shardTransactionIdleTimeoutInMinutes;
+        this.operationTimeoutInSeconds = operationTimeoutInSeconds;
     }
 
     public int getMaxShardDataChangeListenerQueueSize() {
@@ -50,4 +53,8 @@ public class DistributedDataStoreProperties {
     public int getShardTransactionIdleTimeoutInMinutes() {
         return shardTransactionIdleTimeoutInMinutes;
     }
+
+    public int getOperationTimeoutInSeconds() {
+        return operationTimeoutInSeconds;
+    }
 }
index abcde747b93b132f8c492f25ac8af43f96c84a26..6a6a181b6c03ac744d02a3e8e815011d2cf99c3f 100644 (file)
@@ -14,6 +14,7 @@ import akka.actor.Props;
 import akka.event.Logging;
 import akka.event.LoggingAdapter;
 import akka.japi.Creator;
+import akka.persistence.RecoveryFailure;
 import akka.serialization.Serialization;
 
 import com.google.common.base.Optional;
@@ -21,7 +22,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-
+import com.google.protobuf.ByteString;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardTransactionIdentifier;
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardMBeanFactory;
@@ -96,16 +97,17 @@ public class Shard extends RaftActor {
 
     private final List<ActorSelection> dataChangeListeners = new ArrayList<>();
 
-    private final ShardContext shardContext;
+    private final DatastoreContext datastoreContext;
+
 
     private SchemaContext schemaContext;
 
     private Shard(ShardIdentifier name, Map<ShardIdentifier, String> peerAddresses,
-            ShardContext shardContext) {
+            DatastoreContext datastoreContext) {
         super(name.toString(), mapPeerAddresses(peerAddresses), Optional.of(configParams));
 
         this.name = name;
-        this.shardContext = shardContext;
+        this.datastoreContext = datastoreContext;
 
         String setting = System.getProperty("shard.persistent");
 
@@ -114,10 +116,11 @@ public class Shard extends RaftActor {
         LOG.info("Shard created : {} persistent : {}", name, persistent);
 
         store = InMemoryDOMDataStoreFactory.create(name.toString(), null,
-                shardContext.getDataStoreProperties());
+                datastoreContext.getDataStoreProperties());
 
         shardMBean = ShardMBeanFactory.getShardStatsMBean(name.toString());
 
+
     }
 
     private static Map<String, String> mapPeerAddresses(
@@ -134,16 +137,27 @@ public class Shard extends RaftActor {
 
     public static Props props(final ShardIdentifier name,
         final Map<ShardIdentifier, String> peerAddresses,
-        ShardContext shardContext) {
+        DatastoreContext datastoreContext) {
         Preconditions.checkNotNull(name, "name should not be null");
         Preconditions.checkNotNull(peerAddresses, "peerAddresses should not be null");
-        Preconditions.checkNotNull(shardContext, "shardContext should not be null");
+        Preconditions.checkNotNull(datastoreContext, "shardContext should not be null");
 
-        return Props.create(new ShardCreator(name, peerAddresses, shardContext));
+        return Props.create(new ShardCreator(name, peerAddresses, datastoreContext));
+    }
+
+    @Override public void onReceiveRecover(Object message) {
+        LOG.debug("onReceiveRecover: Received message {} from {}", message.getClass().toString(),
+            getSender());
+
+        if (message instanceof RecoveryFailure){
+            LOG.error(((RecoveryFailure) message).cause(), "Recovery failed because of this cause");
+        } else {
+            super.onReceiveRecover(message);
+        }
     }
 
     @Override public void onReceiveCommand(Object message) {
-        LOG.debug("Received message {} from {}", message.getClass().toString(),
+        LOG.debug("onReceiveCommand: Received message {} from {}", message.getClass().toString(),
             getSender());
 
         if (message.getClass()
@@ -185,7 +199,7 @@ public class Shard extends RaftActor {
 
             return getContext().actorOf(
                 ShardTransaction.props(store.newReadOnlyTransaction(), getSelf(),
-                        schemaContext, shardContext), transactionId.toString());
+                        schemaContext,datastoreContext, name.toString()), transactionId.toString());
 
         } else if (createTransaction.getTransactionType()
             == TransactionProxy.TransactionType.READ_WRITE.ordinal()) {
@@ -194,7 +208,7 @@ public class Shard extends RaftActor {
 
             return getContext().actorOf(
                 ShardTransaction.props(store.newReadWriteTransaction(), getSelf(),
-                        schemaContext, shardContext), transactionId.toString());
+                        schemaContext, datastoreContext,name.toString()), transactionId.toString());
 
 
         } else if (createTransaction.getTransactionType()
@@ -204,7 +218,7 @@ public class Shard extends RaftActor {
 
             return getContext().actorOf(
                 ShardTransaction.props(store.newWriteOnlyTransaction(), getSelf(),
-                        schemaContext, shardContext), transactionId.toString());
+                        schemaContext, datastoreContext, name.toString()), transactionId.toString());
         } else {
             throw new IllegalArgumentException(
                 "Shard="+name + ":CreateTransaction message has unidentified transaction type="
@@ -226,7 +240,8 @@ public class Shard extends RaftActor {
             .tell(new CreateTransactionReply(
                     Serialization.serializedActorPath(transactionActor),
                     createTransaction.getTransactionId()).toSerializable(),
-                getSelf());
+                getSelf()
+            );
     }
 
     private void commit(final ActorRef sender, Object serialized) {
@@ -264,9 +279,9 @@ public class Shard extends RaftActor {
         Futures.addCallback(future, new FutureCallback<Void>() {
             @Override
             public void onSuccess(Void v) {
-               sender.tell(new CommitTransactionReply().toSerializable(),self);
-               shardMBean.incrementCommittedTransactionCount();
-               shardMBean.setLastCommittedTransactionTime(new Date());
+                sender.tell(new CommitTransactionReply().toSerializable(), self);
+                shardMBean.incrementCommittedTransactionCount();
+                shardMBean.setLastCommittedTransactionTime(new Date());
             }
 
             @Override
@@ -343,7 +358,7 @@ public class Shard extends RaftActor {
     private void createTransactionChain() {
         DOMStoreTransactionChain chain = store.createTransactionChain();
         ActorRef transactionChain = getContext().actorOf(
-                ShardTransactionChain.props(chain, schemaContext, shardContext));
+                ShardTransactionChain.props(chain, schemaContext, datastoreContext,name.toString() ));
         getSender().tell(new CreateTransactionChainReply(transactionChain.path()).toSerializable(),
                 getSelf());
     }
@@ -363,7 +378,6 @@ public class Shard extends RaftActor {
                     identifier, clientActor.path().toString());
             }
 
-
         } else {
             LOG.error("Unknown state received {}", data);
         }
@@ -381,11 +395,11 @@ public class Shard extends RaftActor {
 
     }
 
-    @Override protected Object createSnapshot() {
+    @Override protected void createSnapshot() {
         throw new UnsupportedOperationException("createSnapshot");
     }
 
-    @Override protected void applySnapshot(Object snapshot) {
+    @Override protected void applySnapshot(ByteString snapshot) {
         throw new UnsupportedOperationException("applySnapshot");
     }
 
@@ -423,18 +437,18 @@ public class Shard extends RaftActor {
 
         final ShardIdentifier name;
         final Map<ShardIdentifier, String> peerAddresses;
-        final ShardContext shardContext;
+        final DatastoreContext datastoreContext;
 
         ShardCreator(ShardIdentifier name, Map<ShardIdentifier, String> peerAddresses,
-                ShardContext shardContext) {
+                DatastoreContext datastoreContext) {
             this.name = name;
             this.peerAddresses = peerAddresses;
-            this.shardContext = shardContext;
+            this.datastoreContext = datastoreContext;
         }
 
         @Override
         public Shard create() throws Exception {
-            return new Shard(name, peerAddresses, shardContext);
+            return new Shard(name, peerAddresses, datastoreContext);
         }
     }
 }
index c9b7c07e9a3a44d1b0c64425122e53a5b3199543..e51d49bff2aff8b6380081e0e772765d172246b0 100644 (file)
@@ -33,6 +33,7 @@ import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound;
 import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound;
 import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
 
+import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
 import scala.concurrent.duration.Duration;
 
 import java.util.ArrayList;
@@ -71,19 +72,19 @@ public class ShardManager extends AbstractUntypedActor {
 
     private ShardManagerInfoMBean mBean;
 
-    private final ShardContext shardContext;
+    private final DatastoreContext datastoreContext;
 
     /**
      * @param type defines the kind of data that goes into shards created by this shard manager. Examples of type would be
      *             configuration or operational
      */
     private ShardManager(String type, ClusterWrapper cluster, Configuration configuration,
-            ShardContext shardContext) {
+            DatastoreContext datastoreContext) {
 
         this.type = Preconditions.checkNotNull(type, "type should not be null");
         this.cluster = Preconditions.checkNotNull(cluster, "cluster should not be null");
         this.configuration = Preconditions.checkNotNull(configuration, "configuration should not be null");
-        this.shardContext = shardContext;
+        this.datastoreContext = datastoreContext;
 
         // Subscribe this actor to cluster member events
         cluster.subscribeToMemberEvents(getSelf());
@@ -96,13 +97,13 @@ public class ShardManager extends AbstractUntypedActor {
     public static Props props(final String type,
         final ClusterWrapper cluster,
         final Configuration configuration,
-        final ShardContext shardContext) {
+        final DatastoreContext datastoreContext) {
 
         Preconditions.checkNotNull(type, "type should not be null");
         Preconditions.checkNotNull(cluster, "cluster should not be null");
         Preconditions.checkNotNull(configuration, "configuration should not be null");
 
-        return Props.create(new ShardManagerCreator(type, cluster, configuration, shardContext));
+        return Props.create(new ShardManagerCreator(type, cluster, configuration, datastoreContext));
     }
 
     @Override
@@ -244,8 +245,9 @@ public class ShardManager extends AbstractUntypedActor {
             ShardIdentifier shardId = getShardIdentifier(memberName, shardName);
             Map<ShardIdentifier, String> peerAddresses = getPeerAddresses(shardName);
             ActorRef actor = getContext()
-                .actorOf(Shard.props(shardId, peerAddresses, shardContext),
-                    shardId.toString());
+                .actorOf(Shard.props(shardId, peerAddresses, datastoreContext).
+                    withMailbox(ActorContext.MAILBOX), shardId.toString());
+
             localShardActorNames.add(shardId.toString());
             localShards.put(shardName, new ShardInformation(shardName, actor, peerAddresses));
         }
@@ -352,19 +354,19 @@ public class ShardManager extends AbstractUntypedActor {
         final String type;
         final ClusterWrapper cluster;
         final Configuration configuration;
-        final ShardContext shardContext;
+        final DatastoreContext datastoreContext;
 
         ShardManagerCreator(String type, ClusterWrapper cluster,
-                Configuration configuration, ShardContext shardContext) {
+                Configuration configuration, DatastoreContext datastoreContext) {
             this.type = type;
             this.cluster = cluster;
             this.configuration = configuration;
-            this.shardContext = shardContext;
+            this.datastoreContext = datastoreContext;
         }
 
         @Override
         public ShardManager create() throws Exception {
-            return new ShardManager(type, cluster, configuration, shardContext);
+            return new ShardManager(type, cluster, configuration, datastoreContext);
         }
     }
 }
index c54d3739b22c3b42d2a93c368afd3eb947ce681b..91d629432f41f7633d128dd6c17e03a283c6bc18 100644 (file)
@@ -26,8 +26,8 @@ public class ShardReadTransaction extends ShardTransaction {
     private final DOMStoreReadTransaction transaction;
 
     public ShardReadTransaction(DOMStoreReadTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext) {
-        super(shardActor, schemaContext);
+            SchemaContext schemaContext,String shardName) {
+        super(shardActor, schemaContext, shardName);
         this.transaction = transaction;
     }
 
index 1dc9ce0a3ecd99f552c13cf19ec9ff393ebdfd51..bd71c27fd67d8b2d2b9d99808a82f91f878d35fc 100644 (file)
@@ -30,8 +30,8 @@ public class ShardReadWriteTransaction extends ShardTransaction {
     private final DOMStoreReadWriteTransaction transaction;
 
     public ShardReadWriteTransaction(DOMStoreReadWriteTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext) {
-        super(shardActor, schemaContext);
+            SchemaContext schemaContext,String shardName) {
+        super(shardActor, schemaContext, shardName);
         this.transaction = transaction;
     }
 
index 365960713dc84754258b364765d0c0f0b794d83b..3b0e0934d9b67c6a18fde38edeb27ae7e92e52f4 100644 (file)
@@ -13,11 +13,10 @@ import akka.actor.PoisonPill;
 import akka.actor.Props;
 import akka.actor.ReceiveTimeout;
 import akka.japi.Creator;
-
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-
 import org.opendaylight.controller.cluster.datastore.exceptions.UnknownMessageException;
+import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardMBeanFactory;
 import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.DataExists;
@@ -74,18 +73,22 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
 
     private final ActorRef shardActor;
     protected final SchemaContext schemaContext;
+    private final String  shardName;
+
 
     private final MutableCompositeModification modification = new MutableCompositeModification();
 
-    protected ShardTransaction(ActorRef shardActor, SchemaContext schemaContext) {
+    protected ShardTransaction(ActorRef shardActor, SchemaContext schemaContext,
+        String shardName) {
         this.shardActor = shardActor;
         this.schemaContext = schemaContext;
+        this.shardName = shardName;
     }
 
     public static Props props(DOMStoreTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext, ShardContext shardContext) {
+            SchemaContext schemaContext,DatastoreContext datastoreContext, String shardName) {
         return Props.create(new ShardTransactionCreator(transaction, shardActor, schemaContext,
-                shardContext));
+           datastoreContext, shardName));
     }
 
     protected abstract DOMStoreTransaction getDOMStoreTransaction();
@@ -134,7 +137,8 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
                         sender.tell(new ReadDataReply(schemaContext,null).toSerializable(), self);
                     }
                 } catch (Exception e) {
-                    sender.tell(new akka.actor.Status.Failure(e),self);
+                    ShardMBeanFactory.getShardStatsMBean(shardName).incrementFailedReadTransactionsCount();
+                    sender.tell(new akka.actor.Status.Failure(e), self);
                 }
 
             }
@@ -192,7 +196,7 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
     protected void readyTransaction(DOMStoreWriteTransaction transaction, ReadyTransaction message) {
         DOMStoreThreePhaseCommitCohort cohort =  transaction.ready();
         ActorRef cohortActor = getContext().actorOf(
-                ThreePhaseCommitCohort.props(cohort, shardActor, modification), "cohort");
+            ThreePhaseCommitCohort.props(cohort, shardActor, modification, shardName), "cohort");
         getSender()
         .tell(new ReadyTransactionReply(cohortActor.path()).toSerializable(), getSelf());
 
@@ -205,14 +209,16 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
         final DOMStoreTransaction transaction;
         final ActorRef shardActor;
         final SchemaContext schemaContext;
-        final ShardContext shardContext;
+        final DatastoreContext datastoreContext;
+        final String shardName;
 
         ShardTransactionCreator(DOMStoreTransaction transaction, ActorRef shardActor,
-                SchemaContext schemaContext, ShardContext actorContext) {
+                SchemaContext schemaContext, DatastoreContext datastoreContext, String shardName) {
             this.transaction = transaction;
             this.shardActor = shardActor;
-            this.shardContext = actorContext;
+            this.shardName = shardName;
             this.schemaContext = schemaContext;
+            this.datastoreContext = datastoreContext;
         }
 
         @Override
@@ -220,16 +226,16 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
             ShardTransaction tx;
             if(transaction instanceof DOMStoreReadWriteTransaction) {
                 tx = new ShardReadWriteTransaction((DOMStoreReadWriteTransaction)transaction,
-                        shardActor, schemaContext);
+                        shardActor, schemaContext, shardName);
             } else if(transaction instanceof DOMStoreReadTransaction) {
                 tx = new ShardReadTransaction((DOMStoreReadTransaction)transaction, shardActor,
-                        schemaContext);
+                        schemaContext, shardName);
             } else {
                 tx = new ShardWriteTransaction((DOMStoreWriteTransaction)transaction,
-                        shardActor, schemaContext);
+                        shardActor, schemaContext, shardName);
             }
 
-            tx.getContext().setReceiveTimeout(shardContext.getShardTransactionIdleTimeout());
+            tx.getContext().setReceiveTimeout(datastoreContext.getShardTransactionIdleTimeout());
             return tx;
         }
     }
index 42bd257ad1cdb97b3d28ab2588bbe6161894b8e9..e7a181865e70c54917a272a6268704316111d13c 100644 (file)
@@ -25,14 +25,16 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 public class ShardTransactionChain extends AbstractUntypedActor {
 
     private final DOMStoreTransactionChain chain;
-    private final ShardContext shardContext;
+    private final DatastoreContext datastoreContext;
     private final SchemaContext schemaContext;
+    private final String shardName;
 
     public ShardTransactionChain(DOMStoreTransactionChain chain, SchemaContext schemaContext,
-            ShardContext shardContext) {
+            DatastoreContext datastoreContext,String shardName) {
         this.chain = chain;
-        this.shardContext = shardContext;
+        this.datastoreContext = datastoreContext;
         this.schemaContext = schemaContext;
+        this.shardName = shardName;
     }
 
     @Override
@@ -58,17 +60,17 @@ public class ShardTransactionChain extends AbstractUntypedActor {
                 TransactionProxy.TransactionType.READ_ONLY.ordinal()) {
             return getContext().actorOf(
                     ShardTransaction.props( chain.newReadOnlyTransaction(), getShardActor(),
-                            schemaContext, shardContext), transactionId);
+                            schemaContext, datastoreContext,shardName), transactionId);
         } else if (createTransaction.getTransactionType() ==
                 TransactionProxy.TransactionType.READ_WRITE.ordinal()) {
             return getContext().actorOf(
                     ShardTransaction.props( chain.newReadWriteTransaction(), getShardActor(),
-                            schemaContext, shardContext), transactionId);
+                            schemaContext, datastoreContext,shardName), transactionId);
         } else if (createTransaction.getTransactionType() ==
                 TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) {
             return getContext().actorOf(
                     ShardTransaction.props( chain.newWriteOnlyTransaction(), getShardActor(),
-                            schemaContext, shardContext), transactionId);
+                            schemaContext, datastoreContext,shardName), transactionId);
         } else {
             throw new IllegalArgumentException (
                     "CreateTransaction message has unidentified transaction type=" +
@@ -85,27 +87,30 @@ public class ShardTransactionChain extends AbstractUntypedActor {
     }
 
     public static Props props(DOMStoreTransactionChain chain, SchemaContext schemaContext,
-            ShardContext shardContext) {
-        return Props.create(new ShardTransactionChainCreator(chain, schemaContext, shardContext));
+        DatastoreContext datastoreContext, String shardName) {
+        return Props.create(new ShardTransactionChainCreator(chain, schemaContext, datastoreContext, shardName));
     }
 
     private static class ShardTransactionChainCreator implements Creator<ShardTransactionChain> {
         private static final long serialVersionUID = 1L;
 
         final DOMStoreTransactionChain chain;
-        final ShardContext shardContext;
+        final DatastoreContext datastoreContext;
         final SchemaContext schemaContext;
+        final String shardName;
+
 
         ShardTransactionChainCreator(DOMStoreTransactionChain chain, SchemaContext schemaContext,
-                ShardContext shardContext) {
+            DatastoreContext datastoreContext, String shardName) {
             this.chain = chain;
-            this.shardContext = shardContext;
+            this.datastoreContext = datastoreContext;
             this.schemaContext = schemaContext;
+            this.shardName = shardName;
         }
 
         @Override
         public ShardTransactionChain create() throws Exception {
-            return new ShardTransactionChain(chain, schemaContext, shardContext);
+            return new ShardTransactionChain(chain, schemaContext, datastoreContext,shardName);
         }
     }
 }
index 8b4d576163c94b873a3fd09ed99bd580392813bc..41c46c3375c58c6177f91b4e397daafaf426b064 100644 (file)
@@ -28,8 +28,8 @@ public class ShardWriteTransaction extends ShardTransaction {
     private final DOMStoreWriteTransaction transaction;
 
     public ShardWriteTransaction(DOMStoreWriteTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext) {
-        super(shardActor, schemaContext);
+            SchemaContext schemaContext,String shardName) {
+        super(shardActor, schemaContext, shardName);
         this.transaction = transaction;
     }
 
index d0c29294cbea9b992644817436ad21fb5f81d46b..5a6d0eca5c2a159963febc4ee9d6436f2e864a5d 100644 (file)
@@ -19,6 +19,7 @@ import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
+import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardMBeanFactory;
 import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction;
@@ -34,21 +35,25 @@ public class ThreePhaseCommitCohort extends AbstractUntypedActor {
     private final DOMStoreThreePhaseCommitCohort cohort;
     private final ActorRef shardActor;
     private final CompositeModification modification;
+    private final String shardName;
 
     public ThreePhaseCommitCohort(DOMStoreThreePhaseCommitCohort cohort,
-        ActorRef shardActor, CompositeModification modification) {
+        ActorRef shardActor, CompositeModification modification,String shardName) {
 
         this.cohort = cohort;
         this.shardActor = shardActor;
         this.modification = modification;
+        this.shardName = shardName;
     }
 
     private final LoggingAdapter log =
         Logging.getLogger(getContext().system(), this);
 
     public static Props props(final DOMStoreThreePhaseCommitCohort cohort,
-        final ActorRef shardActor, final CompositeModification modification) {
-        return Props.create(new ThreePhaseCommitCohortCreator(cohort, shardActor, modification));
+        final ActorRef shardActor, final CompositeModification modification,
+        String shardName) {
+        return Props.create(new ThreePhaseCommitCohortCreator(cohort, shardActor, modification,
+           shardName));
     }
 
     @Override
@@ -78,9 +83,10 @@ public class ThreePhaseCommitCohort extends AbstractUntypedActor {
         Futures.addCallback(future, new FutureCallback<Void>() {
             @Override
             public void onSuccess(Void v) {
+                ShardMBeanFactory.getShardStatsMBean(shardName).incrementAbortTransactionsCount();
                 sender
                     .tell(new AbortTransactionReply().toSerializable(),
-                        self);
+                    self);
             }
 
             @Override
@@ -148,17 +154,19 @@ public class ThreePhaseCommitCohort extends AbstractUntypedActor {
         final DOMStoreThreePhaseCommitCohort cohort;
         final ActorRef shardActor;
         final CompositeModification modification;
+        final String shardName;
 
         ThreePhaseCommitCohortCreator(DOMStoreThreePhaseCommitCohort cohort,
-                ActorRef shardActor, CompositeModification modification) {
+            ActorRef shardActor, CompositeModification modification, String shardName) {
             this.cohort = cohort;
             this.shardActor = shardActor;
             this.modification = modification;
+            this.shardName = shardName;
         }
 
         @Override
         public ThreePhaseCommitCohort create() throws Exception {
-            return new ThreePhaseCommitCohort(cohort, shardActor, modification);
+            return new ThreePhaseCommitCohort(cohort, shardActor, modification, shardName);
         }
     }
 }
index c557118b1e8f92234d597ce6372cda2674f6a6bd..a5be69531d73ede89f7bba5978a85d2e045d8989 100644 (file)
@@ -151,8 +151,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
 
             ActorSelection cohort = actorContext.actorSelection(actorPath);
 
-            futureList.add(actorContext.executeRemoteOperationAsync(cohort, message,
-                    ActorContext.ASK_DURATION));
+            futureList.add(actorContext.executeRemoteOperationAsync(cohort, message));
         }
 
         return Futures.sequence(futureList, actorContext.getActorSystem().dispatcher());
index f447f3c718980285d32e79c5a9b2579e26309971..a8b20c030e1dd34f274ce2e02b56669739824af3 100644 (file)
@@ -249,7 +249,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
         Preconditions.checkState(transactionType != TransactionType.READ_ONLY,
                 "Modification operation on read-only transaction is not allowed");
         Preconditions.checkState(!inReadyState,
-                "Transaction is sealed - further modifications are allowed");
+                "Transaction is sealed - further modifications are not allowed");
     }
 
     @Override
@@ -353,8 +353,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
 
         try {
             Object response = actorContext.executeShardOperation(shardName,
-                new CreateTransaction(identifier.toString(),this.transactionType.ordinal() ).toSerializable(),
-                ActorContext.ASK_DURATION);
+                new CreateTransaction(identifier.toString(),this.transactionType.ordinal() ).toSerializable());
             if (response.getClass().equals(CreateTransactionReply.SERIALIZABLE_CLASS)) {
                 CreateTransactionReply reply =
                     CreateTransactionReply.fromSerializable(response);
@@ -472,7 +471,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             // Send the ReadyTransaction message to the Tx actor.
 
             final Future<Object> replyFuture = actorContext.executeRemoteOperationAsync(getActor(),
-                    new ReadyTransaction().toSerializable(), ActorContext.ASK_DURATION);
+                    new ReadyTransaction().toSerializable());
 
             // Combine all the previously recorded put/merge/delete operation reply Futures and the
             // ReadyTransactionReply Future into one Future. If any one fails then the combined
@@ -532,23 +531,21 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
         public void deleteData(YangInstanceIdentifier path) {
             LOG.debug("Tx {} deleteData called path = {}", identifier, path);
             recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(),
-                    new DeleteData(path).toSerializable(), ActorContext.ASK_DURATION ));
+                    new DeleteData(path).toSerializable() ));
         }
 
         @Override
         public void mergeData(YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
             LOG.debug("Tx {} mergeData called path = {}", identifier, path);
             recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(),
-                    new MergeData(path, data, schemaContext).toSerializable(),
-                    ActorContext.ASK_DURATION));
+                    new MergeData(path, data, schemaContext).toSerializable()));
         }
 
         @Override
         public void writeData(YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
             LOG.debug("Tx {} writeData called path = {}", identifier, path);
             recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(),
-                    new WriteData(path, data, schemaContext).toSerializable(),
-                    ActorContext.ASK_DURATION));
+                    new WriteData(path, data, schemaContext).toSerializable()));
         }
 
         @Override
@@ -612,6 +609,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
 
                         returnFuture.setException(new ReadFailedException(
                                 "Error reading data for path " + path, failure));
+
                     } else {
                         LOG.debug("Tx {} read operation succeeded", identifier, failure);
 
@@ -633,7 +631,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             };
 
             Future<Object> readFuture = actorContext.executeRemoteOperationAsync(getActor(),
-                    new ReadData(path).toSerializable(), ActorContext.ASK_DURATION);
+                    new ReadData(path).toSerializable());
             readFuture.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
         }
 
@@ -714,7 +712,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             };
 
             Future<Object> future = actorContext.executeRemoteOperationAsync(getActor(),
-                    new DataExists(path).toSerializable(), ActorContext.ASK_DURATION);
+                    new DataExists(path).toSerializable());
             future.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
         }
     }
index afca87f0df6458a041b8d2219e3e578066513481..2a409c0300889cb34586524fa12d2381b15f4a8b 100644 (file)
@@ -1,11 +1,18 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard;
 
 import java.util.HashMap;
 import java.util.Map;
 
 /**
- * @author: syedbahm
- * Date: 7/16/14
+ * @author Basheeruddin syedbahm@cisco.com
+ *
  */
 public class ShardMBeanFactory {
     private static Map<String, ShardStats> shardMBeans =
index c6c1579ce336dc78e64ecc6b79042c30eee28148..22ad8e7f5a3408ff7457876635ced85f19ad2842 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
 package org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard;
 
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.AbstractBaseMBean;
@@ -6,37 +14,41 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 
 /**
- * @author: syedbahm
+ * @author  Basheeruddin syedbahm@cisco.com
  */
 public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean {
 
     private final String shardName;
 
-    private Long committedTransactionsCount = 0L;
+    private long committedTransactionsCount = 0L;
 
-    private Long readOnlyTransactionCount = 0L;
+    private long readOnlyTransactionCount = 0L;
 
-    private Long writeOnlyTransactionCount = 0L;
+    private long writeOnlyTransactionCount = 0L;
 
-    private Long readWriteTransactionCount = 0L;
+    private long readWriteTransactionCount = 0L;
 
     private String leader;
 
     private String raftState;
 
-    private Long lastLogTerm = -1L;
+    private long lastLogTerm = -1L;
 
-    private Long lastLogIndex = -1L;
+    private long lastLogIndex = -1L;
 
-    private Long currentTerm = -1L;
+    private long currentTerm = -1L;
 
-    private Long commitIndex = -1L;
+    private long commitIndex = -1L;
 
-    private Long lastApplied = -1L;
+    private long lastApplied = -1L;
 
     private Date lastCommittedTransactionTime = new Date(0L);
 
-    private Long failedTransactionsCount = 0L;
+    private long failedTransactionsCount = 0L;
+
+    private long failedReadTransactionsCount = 0L;
+
+    private long abortTransactionsCount = 0L;
 
     private SimpleDateFormat sdf =
         new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -52,7 +64,7 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean {
     }
 
     @Override
-    public Long getCommittedTransactionsCount() {
+    public long getCommittedTransactionsCount() {
         return committedTransactionsCount;
     }
 
@@ -64,35 +76,35 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean {
         return raftState;
     }
 
-    @Override public Long getReadOnlyTransactionCount() {
+    @Override public long getReadOnlyTransactionCount() {
         return readOnlyTransactionCount;
     }
 
-    @Override public Long getWriteOnlyTransactionCount() {
+    @Override public long getWriteOnlyTransactionCount() {
         return writeOnlyTransactionCount;
     }
 
-    @Override public Long getReadWriteTransactionCount() {
+    @Override public long getReadWriteTransactionCount() {
         return readWriteTransactionCount;
     }
 
-    @Override public Long getLastLogIndex() {
+    @Override public long getLastLogIndex() {
         return lastLogIndex;
     }
 
-    @Override public Long getLastLogTerm() {
+    @Override public long getLastLogTerm() {
         return lastLogTerm;
     }
 
-    @Override public Long getCurrentTerm() {
+    @Override public long getCurrentTerm() {
         return currentTerm;
     }
 
-    @Override public Long getCommitIndex() {
+    @Override public long getCommitIndex() {
         return commitIndex;
     }
 
-    @Override public Long getLastApplied() {
+    @Override public long getLastApplied() {
         return lastApplied;
     }
 
@@ -102,26 +114,44 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean {
         return sdf.format(lastCommittedTransactionTime);
     }
 
-    @Override public Long getFailedTransactionsCount() {
+    @Override public long getFailedTransactionsCount() {
         return failedTransactionsCount;
     }
 
-    public Long incrementCommittedTransactionCount() {
+    @Override public long getFailedReadTransactionsCount() {
+        return failedReadTransactionsCount;
+    }
+
+    @Override public long getAbortTransactionsCount() {
+        return abortTransactionsCount;
+    }
+
+    public long incrementCommittedTransactionCount() {
         return committedTransactionsCount++;
     }
 
-    public Long incrementReadOnlyTransactionCount() {
+    public long incrementReadOnlyTransactionCount() {
         return readOnlyTransactionCount++;
     }
 
-    public Long incrementWriteOnlyTransactionCount() {
+    public long incrementWriteOnlyTransactionCount() {
         return writeOnlyTransactionCount++;
     }
 
-    public Long incrementReadWriteTransactionCount() {
+    public long incrementReadWriteTransactionCount() {
         return readWriteTransactionCount++;
     }
 
+    public long incrementFailedTransactionsCount() {
+        return failedTransactionsCount++;
+    }
+
+    public long incrementFailedReadTransactionsCount() {
+        return failedReadTransactionsCount++;
+    }
+
+    public long incrementAbortTransactionsCount () { return abortTransactionsCount++;}
+
     public void setLeader(String leader) {
         this.leader = leader;
     }
@@ -130,23 +160,23 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean {
         this.raftState = raftState;
     }
 
-    public void setLastLogTerm(Long lastLogTerm) {
+    public void setLastLogTerm(long lastLogTerm) {
         this.lastLogTerm = lastLogTerm;
     }
 
-    public void setLastLogIndex(Long lastLogIndex) {
+    public void setLastLogIndex(long lastLogIndex) {
         this.lastLogIndex = lastLogIndex;
     }
 
-    public void setCurrentTerm(Long currentTerm) {
+    public void setCurrentTerm(long currentTerm) {
         this.currentTerm = currentTerm;
     }
 
-    public void setCommitIndex(Long commitIndex) {
+    public void setCommitIndex(long commitIndex) {
         this.commitIndex = commitIndex;
     }
 
-    public void setLastApplied(Long lastApplied) {
+    public void setLastApplied(long lastApplied) {
         this.lastApplied = lastApplied;
     }
 
@@ -171,8 +201,28 @@ public class ShardStats extends AbstractBaseMBean implements ShardStatsMBean {
         return JMX_CATEGORY_SHARD;
     }
 
+    /**
+     * resets the counters related to transactions
+     */
+
+    public void resetTransactionCounters(){
+        committedTransactionsCount = 0L;
+
+        readOnlyTransactionCount = 0L;
+
+        writeOnlyTransactionCount = 0L;
+
+        readWriteTransactionCount = 0L;
+
+        lastCommittedTransactionTime = new Date(0L);
+
+        failedTransactionsCount = 0L;
+
+        failedReadTransactionsCount = 0L;
+
+        abortTransactionsCount = 0L;
 
-    public void incrementFailedTransactionsCount() {
-        this.failedTransactionsCount++;
     }
+
+
 }
index b8b220ee82fae3851e1f8bcc70a04f74b1c31560..c16f8421bfb3f7ea8e75ab9bd366859693ff98a8 100644 (file)
@@ -6,30 +6,36 @@ package org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard;
 public interface ShardStatsMBean {
     String getShardName();
 
-    Long getCommittedTransactionsCount();
+    long getCommittedTransactionsCount();
 
     String getLeader();
 
     String getRaftState();
 
-    Long getReadOnlyTransactionCount();
+    long getReadOnlyTransactionCount();
 
-    Long getWriteOnlyTransactionCount();
+    long getWriteOnlyTransactionCount();
 
-    Long getReadWriteTransactionCount();
+    long getReadWriteTransactionCount();
 
-    Long getLastLogIndex();
+    long getLastLogIndex();
 
-    Long getLastLogTerm();
+    long getLastLogTerm();
 
-    Long getCurrentTerm();
+    long getCurrentTerm();
 
-    Long getCommitIndex();
+    long getCommitIndex();
 
-    Long getLastApplied();
+    long getLastApplied();
 
     String getLastCommittedTransactionTime();
 
-    Long getFailedTransactionsCount();
+    long getFailedTransactionsCount();
+
+    long getFailedReadTransactionsCount();
+
+    long getAbortTransactionsCount();
+
+    void resetTransactionCounters();
 
 }
index f76430f5a1cb1cdb9e84f3b92f85c923a7111967..b87dc4f608b191c21d5fa34b8bf4a9744864f96a 100644 (file)
@@ -47,16 +47,17 @@ public class ActorContext {
     private static final Logger
         LOG = LoggerFactory.getLogger(ActorContext.class);
 
-    public static final FiniteDuration ASK_DURATION =
-        Duration.create(5, TimeUnit.SECONDS);
-    public static final Duration AWAIT_DURATION =
-        Duration.create(5, TimeUnit.SECONDS);
+    private static final FiniteDuration DEFAULT_OPER_DURATION = Duration.create(5, TimeUnit.SECONDS);
+
+    public static final String MAILBOX = "bounded-mailbox";
 
     private final ActorSystem actorSystem;
     private final ActorRef shardManager;
     private final ClusterWrapper clusterWrapper;
     private final Configuration configuration;
     private volatile SchemaContext schemaContext;
+    private FiniteDuration operationDuration = DEFAULT_OPER_DURATION;
+    private Timeout operationTimeout = new Timeout(operationDuration);
 
     public ActorContext(ActorSystem actorSystem, ActorRef shardManager,
         ClusterWrapper clusterWrapper,
@@ -91,6 +92,11 @@ public class ActorContext {
         }
     }
 
+    public void setOperationTimeout(int timeoutInSeconds) {
+        operationDuration = Duration.create(timeoutInSeconds, TimeUnit.SECONDS);
+        operationTimeout = new Timeout(operationDuration);
+    }
+
     public SchemaContext getSchemaContext() {
         return schemaContext;
     }
@@ -115,7 +121,7 @@ public class ActorContext {
      */
     public ActorRef findLocalShard(String shardName) {
         Object result = executeLocalOperation(shardManager,
-            new FindLocalShard(shardName), ASK_DURATION);
+            new FindLocalShard(shardName));
 
         if (result instanceof LocalShardFound) {
             LocalShardFound found = (LocalShardFound) result;
@@ -131,7 +137,7 @@ public class ActorContext {
 
     public String findPrimaryPath(String shardName) {
         Object result = executeLocalOperation(shardManager,
-            new FindPrimary(shardName).toSerializable(), ASK_DURATION);
+            new FindPrimary(shardName).toSerializable());
 
         if (result.getClass().equals(PrimaryFound.SERIALIZABLE_CLASS)) {
             PrimaryFound found = PrimaryFound.fromSerializable(result);
@@ -149,16 +155,13 @@ public class ActorContext {
      *
      * @param actor
      * @param message
-     * @param duration
      * @return The response of the operation
      */
-    public Object executeLocalOperation(ActorRef actor, Object message,
-        FiniteDuration duration) {
-        Future<Object> future =
-            ask(actor, message, new Timeout(duration));
+    public Object executeLocalOperation(ActorRef actor, Object message) {
+        Future<Object> future = ask(actor, message, operationTimeout);
 
         try {
-            return Await.result(future, AWAIT_DURATION);
+            return Await.result(future, operationDuration);
         } catch (Exception e) {
             throw new TimeoutException("Sending message " + message.getClass().toString() + " to actor " + actor.toString() + " failed" , e);
         }
@@ -169,21 +172,19 @@ public class ActorContext {
      *
      * @param actor
      * @param message
-     * @param duration
      * @return
      */
-    public Object executeRemoteOperation(ActorSelection actor, Object message,
-        FiniteDuration duration) {
+    public Object executeRemoteOperation(ActorSelection actor, Object message) {
 
         LOG.debug("Sending remote message {} to {}", message.getClass().toString(), actor.toString());
 
-        Future<Object> future =
-            ask(actor, message, new Timeout(duration));
+        Future<Object> future = ask(actor, message, operationTimeout);
 
         try {
-            return Await.result(future, AWAIT_DURATION);
+            return Await.result(future, operationDuration);
         } catch (Exception e) {
-            throw new TimeoutException("Sending message " + message.getClass().toString() + " to actor " + actor.toString() + " failed" , e);
+            throw new TimeoutException("Sending message " + message.getClass().toString() +
+                    " to actor " + actor.toString() + " failed" , e);
         }
     }
 
@@ -192,15 +193,13 @@ public class ActorContext {
      *
      * @param actor the ActorSelection
      * @param message the message to send
-     * @param duration the maximum amount of time to send he message
      * @return a Future containing the eventual result
      */
-    public Future<Object> executeRemoteOperationAsync(ActorSelection actor, Object message,
-            FiniteDuration duration) {
+    public Future<Object> executeRemoteOperationAsync(ActorSelection actor, Object message) {
 
         LOG.debug("Sending remote message {} to {}", message.getClass().toString(), actor.toString());
 
-        return ask(actor, message, new Timeout(duration));
+        return ask(actor, message, operationTimeout);
     }
 
     /**
@@ -223,16 +222,14 @@ public class ActorContext {
      *
      * @param shardName
      * @param message
-     * @param duration
      * @return
      * @throws org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException         if the message to the remote shard times out
      * @throws org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException if the primary shard is not found
      */
-    public Object executeShardOperation(String shardName, Object message,
-        FiniteDuration duration) {
+    public Object executeShardOperation(String shardName, Object message) {
         ActorSelection primary = findPrimary(shardName);
 
-        return executeRemoteOperation(primary, message, duration);
+        return executeRemoteOperation(primary, message);
     }
 
     /**
@@ -244,19 +241,17 @@ public class ActorContext {
      *
      * @param shardName the name of the shard on which the operation needs to be executed
      * @param message the message that needs to be sent to the shard
-     * @param duration the time duration in which this operation should complete
      * @return the message that was returned by the local actor on which the
      *         the operation was executed. If a local shard was not found then
      *         null is returned
      * @throws org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException
      *         if the operation does not complete in a specified time duration
      */
-    public Object executeLocalShardOperation(String shardName, Object message,
-        FiniteDuration duration) {
+    public Object executeLocalShardOperation(String shardName, Object message) {
         ActorRef local = findLocalShard(shardName);
 
         if(local != null) {
-            return executeLocalOperation(local, message, duration);
+            return executeLocalOperation(local, message);
         }
 
         return null;
index f5a0d3783ab011728ab0688db60b404a9c53719e..e2fbacb46169047764d24f8ba09f087693773d84 100644 (file)
@@ -2,9 +2,12 @@ package org.opendaylight.controller.config.yang.config.distributed_datastore_pro
 
 import org.opendaylight.controller.cluster.datastore.DistributedDataStoreFactory;
 import org.opendaylight.controller.cluster.datastore.DistributedDataStoreProperties;
+import org.osgi.framework.BundleContext;
 
 public class DistributedConfigDataStoreProviderModule extends
     org.opendaylight.controller.config.yang.config.distributed_datastore_provider.AbstractDistributedConfigDataStoreProviderModule {
+    private BundleContext bundleContext;
+
     public DistributedConfigDataStoreProviderModule(
         org.opendaylight.controller.config.api.ModuleIdentifier identifier,
         org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@@ -33,9 +36,15 @@ public class DistributedConfigDataStoreProviderModule extends
         }
 
         return DistributedDataStoreFactory.createInstance("config", getConfigSchemaServiceDependency(),
-                new DistributedDataStoreProperties(props.getMaxShardDataChangeExecutorPoolSize(),
-                        props.getMaxShardDataChangeExecutorQueueSize(),
-                        props.getMaxShardDataChangeListenerQueueSize(),
-                        props.getShardTransactionIdleTimeoutInMinutes()));
+                new DistributedDataStoreProperties(
+                        props.getMaxShardDataChangeExecutorPoolSize().getValue(),
+                        props.getMaxShardDataChangeExecutorQueueSize().getValue(),
+                        props.getMaxShardDataChangeListenerQueueSize().getValue(),
+                        props.getShardTransactionIdleTimeoutInMinutes().getValue(),
+                        props.getOperationTimeoutInSeconds().getValue()), bundleContext);
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
     }
 }
index 67bf5994545af4e8d64b95cf40352bbb908d68a5..0cdaca3a15262883c75ee31c71a121dc0eec0607 100644 (file)
@@ -8,6 +8,29 @@
 * Do not modify this file unless it is present under src/main directory
 */
 package org.opendaylight.controller.config.yang.config.distributed_datastore_provider;
+
+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 DistributedConfigDataStoreProviderModuleFactory extends org.opendaylight.controller.config.yang.config.distributed_datastore_provider.AbstractDistributedConfigDataStoreProviderModuleFactory {
 
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        DistributedConfigDataStoreProviderModule module = (DistributedConfigDataStoreProviderModule)super.createModule(instanceName,dependencyResolver,bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver,
+        DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
+        DistributedConfigDataStoreProviderModule module = (DistributedConfigDataStoreProviderModule)super.createModule(instanceName, dependencyResolver,
+            old, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+
 }
index 443334d11f65378871da7a6f2ae97097d4c2eb87..c185e871ea46cd91f1176a43eda52e9b464d8bd2 100644 (file)
@@ -2,9 +2,12 @@ package org.opendaylight.controller.config.yang.config.distributed_datastore_pro
 
 import org.opendaylight.controller.cluster.datastore.DistributedDataStoreFactory;
 import org.opendaylight.controller.cluster.datastore.DistributedDataStoreProperties;
+import org.osgi.framework.BundleContext;
 
 public class DistributedOperationalDataStoreProviderModule extends
     org.opendaylight.controller.config.yang.config.distributed_datastore_provider.AbstractDistributedOperationalDataStoreProviderModule {
+    private BundleContext bundleContext;
+
     public DistributedOperationalDataStoreProviderModule(
         org.opendaylight.controller.config.api.ModuleIdentifier identifier,
         org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@@ -34,10 +37,16 @@ public class DistributedOperationalDataStoreProviderModule extends
 
         return DistributedDataStoreFactory.createInstance("operational",
                 getOperationalSchemaServiceDependency(),
-                new DistributedDataStoreProperties(props.getMaxShardDataChangeExecutorPoolSize(),
-                        props.getMaxShardDataChangeExecutorQueueSize(),
-                        props.getMaxShardDataChangeListenerQueueSize(),
-                        props.getShardTransactionIdleTimeoutInMinutes()));
+                new DistributedDataStoreProperties(
+                        props.getMaxShardDataChangeExecutorPoolSize().getValue(),
+                        props.getMaxShardDataChangeExecutorQueueSize().getValue(),
+                        props.getMaxShardDataChangeListenerQueueSize().getValue(),
+                        props.getShardTransactionIdleTimeoutInMinutes().getValue(),
+                        props.getOperationTimeoutInSeconds().getValue()), bundleContext);
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
     }
 
 }
index c9965fee09029ee73c6b85687f8f659301680e97..364fe629234612ea58d6c8fb2a9bc7c78ee3e20c 100644 (file)
@@ -8,6 +8,27 @@
 * Do not modify this file unless it is present under src/main directory
 */
 package org.opendaylight.controller.config.yang.config.distributed_datastore_provider;
+
+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 DistributedOperationalDataStoreProviderModuleFactory extends org.opendaylight.controller.config.yang.config.distributed_datastore_provider.AbstractDistributedOperationalDataStoreProviderModuleFactory {
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        DistributedOperationalDataStoreProviderModule module = (DistributedOperationalDataStoreProviderModule)super.createModule(instanceName,dependencyResolver,bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver,
+        DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
+        DistributedOperationalDataStoreProviderModule module = (DistributedOperationalDataStoreProviderModule)super.createModule(instanceName, dependencyResolver,
+            old, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
 
 }
index 8af9bd07d793cfb0eb0dae33414b6631d109e4a9..c29f93bb073cb712df045bf4839cc247a2b49111 100644 (file)
@@ -1,5 +1,10 @@
 
 odl-cluster-data {
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 100ms
+  }
   akka {
     loggers = ["akka.event.slf4j.Slf4jLogger"]
     cluster {
index a9a8a1ad986c65835018f80773707561473934b8..d50be2ca0ef8fdc8123e5b63a62887034bed0bb1 100644 (file)
@@ -36,30 +36,48 @@ module distributed-datastore-provider {
                 config:java-name-prefix DistributedOperationalDataStoreProvider;
      }
 
+    typedef non-zero-uint16-type {
+        type uint16 {
+            range "1..max";
+        }
+    }
+    
+    typedef operation-timeout-type {
+        type uint16 {
+            range "5..max";
+        }
+    }
+    
     grouping data-store-properties {
         leaf max-shard-data-change-executor-queue-size {
             default 1000;
-            type uint16;
+            type non-zero-uint16-type;
             description "The maximum queue size for each shard's data store data change notification executor.";
          }
 
          leaf max-shard-data-change-executor-pool-size {
             default 20;
-            type uint16;
+            type non-zero-uint16-type;
             description "The maximum thread pool size for each shard's data store data change notification executor.";
          }
 
          leaf max-shard-data-change-listener-queue-size {
             default 1000;
-            type uint16;
+            type non-zero-uint16-type;
             description "The maximum queue size for each shard's data store data change listeners.";
          }
          
          leaf shard-transaction-idle-timeout-in-minutes {
             default 10;
-            type uint16;
+            type non-zero-uint16-type;
             description "The maximum amount of time a shard transaction can be idle without receiving any messages before it self-destructs.";
          }
+         
+         leaf operation-timeout-in-seconds {
+            default 5;
+            type operation-timeout-type;
+            description "The maximum amount of time for akka operations (remote or local) to complete before failing.";
+         }
     }
     
     // Augments the 'configuration' choice node under modules/module.
index e70453f2d629857dd92ef24b919395af91c9b742..6f131f301fe8985dade813ce2b00bf994c7a1bf6 100644 (file)
@@ -62,9 +62,9 @@ public class BasicIntegrationTest extends AbstractActorTest {
                     .shardName("inventory").type("config").build();
 
             final SchemaContext schemaContext = TestModel.createTestContext();
-            ShardContext shardContext = new ShardContext();
+            DatastoreContext datastoreContext = new DatastoreContext();
 
-            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, shardContext);
+            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, datastoreContext);
             final ActorRef shard = getSystem().actorOf(props);
 
             new Within(duration("10 seconds")) {
index e653c3d3717351182a6a57cf570c4a6bf6449500..2ed11cfbda21eff65b3cb6223b671731c891ab67 100644 (file)
@@ -82,8 +82,7 @@ public class DataChangeListenerProxyTest extends AbstractActorTest {
         ActorContext
             testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)), new MockClusterWrapper(), new MockConfiguration());
         Object messages = testContext
-            .executeLocalOperation(actorRef, "messages",
-                ActorContext.ASK_DURATION);
+            .executeLocalOperation(actorRef, "messages");
 
         Assert.assertNotNull(messages);
 
index c99a7e8c8c4908133bac2a9710e3549f02e2410c..3d0aaa0082e55e8b73976af4637977dd9111c97d 100644 (file)
@@ -62,8 +62,7 @@ public class DataChangeListenerRegistrationProxyTest extends AbstractActorTest{
         ActorContext
             testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class)),new MockClusterWrapper(), new MockConfiguration());
         Object messages = testContext
-            .executeLocalOperation(actorRef, "messages",
-                ActorContext.ASK_DURATION);
+            .executeLocalOperation(actorRef, "messages");
 
         Assert.assertNotNull(messages);
 
index e6f68c032a325f59bea291e2f17e129fd47da766..1feefd1c1fbcde3381d91332bd8d977048e7e074 100644 (file)
@@ -42,11 +42,11 @@ public class ShardManagerTest {
         new JavaTestKit(system) {{
             final Props props = ShardManager
                 .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new ShardContext());
+                    new MockConfiguration(), new DatastoreContext());
             final TestActorRef<ShardManager> subject =
                 TestActorRef.create(system, props);
 
-            new Within(duration("1 seconds")) {
+            new Within(duration("10 seconds")) {
                 @Override
                 protected void run() {
 
@@ -67,11 +67,11 @@ public class ShardManagerTest {
         new JavaTestKit(system) {{
             final Props props = ShardManager
                 .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new ShardContext());
+                    new MockConfiguration(), new DatastoreContext());
             final TestActorRef<ShardManager> subject =
                 TestActorRef.create(system, props);
 
-            new Within(duration("1 seconds")) {
+            new Within(duration("10 seconds")) {
                 @Override
                 protected void run() {
 
@@ -91,17 +91,17 @@ public class ShardManagerTest {
         new JavaTestKit(system) {{
             final Props props = ShardManager
                 .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new ShardContext());
+                    new MockConfiguration(), new DatastoreContext());
             final TestActorRef<ShardManager> subject =
                 TestActorRef.create(system, props);
 
-            new Within(duration("1 seconds")) {
+            new Within(duration("10 seconds")) {
                 @Override
                 protected void run() {
 
                     subject.tell(new FindLocalShard("inventory"), getRef());
 
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "find local") {
+                    final String out = new ExpectMsg<String>(duration("10 seconds"), "find local") {
                         @Override
                         protected String match(Object in) {
                             if (in instanceof LocalShardNotFound) {
@@ -128,17 +128,17 @@ public class ShardManagerTest {
         new JavaTestKit(system) {{
             final Props props = ShardManager
                 .props("config", mockClusterWrapper,
-                    new MockConfiguration(), new ShardContext());
+                    new MockConfiguration(), new DatastoreContext());
             final TestActorRef<ShardManager> subject =
                 TestActorRef.create(system, props);
 
-            new Within(duration("1 seconds")) {
+            new Within(duration("10 seconds")) {
                 @Override
                 protected void run() {
 
                     subject.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef());
 
-                    final ActorRef out = new ExpectMsg<ActorRef>(duration("1 seconds"), "find local") {
+                    final ActorRef out = new ExpectMsg<ActorRef>(duration("10 seconds"), "find local") {
                         @Override
                         protected ActorRef match(Object in) {
                             if (in instanceof LocalShardFound) {
@@ -164,12 +164,12 @@ public class ShardManagerTest {
         new JavaTestKit(system) {{
             final Props props = ShardManager
                 .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new ShardContext());
+                    new MockConfiguration(), new DatastoreContext());
             final TestActorRef<ShardManager> subject =
                 TestActorRef.create(system, props);
 
             // the run() method needs to finish within 3 seconds
-            new Within(duration("1 seconds")) {
+            new Within(duration("10 seconds")) {
                 @Override
                 protected void run() {
 
@@ -204,12 +204,12 @@ public class ShardManagerTest {
         new JavaTestKit(system) {{
             final Props props = ShardManager
                 .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new ShardContext());
+                    new MockConfiguration(), new DatastoreContext());
             final TestActorRef<ShardManager> subject =
                 TestActorRef.create(system, props);
 
             // the run() method needs to finish within 3 seconds
-            new Within(duration("1 seconds")) {
+            new Within(duration("10 seconds")) {
                 @Override
                 protected void run() {
 
index fc45efcdea854bea791c44b12a4437c2c74bc2f1..4466e50f96f53651be61a696deda5249692196e9 100644 (file)
@@ -35,7 +35,7 @@ import static org.junit.Assert.assertTrue;
 
 public class ShardTest extends AbstractActorTest {
 
-    private static final ShardContext shardContext = new ShardContext();
+    private static final DatastoreContext DATA_STORE_CONTEXT = new DatastoreContext();
 
     @Test
     public void testOnReceiveCreateTransactionChain() throws Exception {
@@ -44,7 +44,7 @@ public class ShardTest extends AbstractActorTest {
                 ShardIdentifier.builder().memberName("member-1")
                     .shardName("inventory").type("config").build();
 
-            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, shardContext);
+            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, DATA_STORE_CONTEXT);
             final ActorRef subject =
                 getSystem().actorOf(props, "testCreateTransactionChain");
 
@@ -103,7 +103,7 @@ public class ShardTest extends AbstractActorTest {
                 ShardIdentifier.builder().memberName("member-1")
                     .shardName("inventory").type("config").build();
 
-            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, shardContext);
+            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, DATA_STORE_CONTEXT);
             final ActorRef subject =
                 getSystem().actorOf(props, "testRegisterChangeListener");
 
@@ -165,7 +165,7 @@ public class ShardTest extends AbstractActorTest {
                 ShardIdentifier.builder().memberName("member-1")
                     .shardName("inventory").type("config").build();
 
-            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, shardContext);
+            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, DATA_STORE_CONTEXT);
             final ActorRef subject =
                 getSystem().actorOf(props, "testCreateTransaction");
 
@@ -227,7 +227,7 @@ public class ShardTest extends AbstractActorTest {
                     .shardName("inventory").type("config").build();
 
             peerAddresses.put(identifier, null);
-            final Props props = Shard.props(identifier, peerAddresses, shardContext);
+            final Props props = Shard.props(identifier, peerAddresses, DATA_STORE_CONTEXT);
             final ActorRef subject =
                 getSystem().actorOf(props, "testPeerAddressResolved");
 
index 0262b8c1457a171c262f5da83dc755d9bcbb174d..71eb1f1603a7b00dfc576ec43f8816a41ef2a1ed 100644 (file)
@@ -28,7 +28,9 @@ public class ShardTransactionChainTest extends AbstractActorTest {
 
     private static final SchemaContext testSchemaContext = TestModel.createTestContext();
 
-    private static final ShardContext shardContext = new ShardContext();
+    private static final DatastoreContext DATA_STORE_CONTEXT = new DatastoreContext();
+
+    private static final String mockShardName = "mockShardName";
 
     @BeforeClass
     public static void staticSetup() {
@@ -39,7 +41,7 @@ public class ShardTransactionChainTest extends AbstractActorTest {
     public void testOnReceiveCreateTransaction() throws Exception {
         new JavaTestKit(getSystem()) {{
             final Props props = ShardTransactionChain.props(store.createTransactionChain(),
-                    testSchemaContext, shardContext);
+                    testSchemaContext, DATA_STORE_CONTEXT, mockShardName);
             final ActorRef subject = getSystem().actorOf(props, "testCreateTransaction");
 
             new Within(duration("1 seconds")) {
@@ -77,7 +79,7 @@ public class ShardTransactionChainTest extends AbstractActorTest {
     public void testOnReceiveCloseTransactionChain() throws Exception {
         new JavaTestKit(getSystem()) {{
             final Props props = ShardTransactionChain.props(store.createTransactionChain(),
-                    testSchemaContext, shardContext);
+                    testSchemaContext, DATA_STORE_CONTEXT,mockShardName );
             final ActorRef subject = getSystem().actorOf(props, "testCloseTransactionChain");
 
             new Within(duration("1 seconds")) {
index 8a6534b87ef5f2e21d735d6299aad58ba3ae24e1..4fe60f6467d2dab4db24dd34df03b4b6d9c9c7d8 100644 (file)
@@ -57,7 +57,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
         ShardIdentifier.builder().memberName("member-1")
             .shardName("inventory").type("operational").build();
 
-    private final ShardContext shardContext = new ShardContext();
+    private final DatastoreContext datastoreContext = new DatastoreContext();
 
     @BeforeClass
     public static void staticSetup() {
@@ -69,9 +69,9 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
         throws Throwable {
 
         final ActorRef shard =
-            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new ShardContext()));
+            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -99,9 +99,9 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
         throws Throwable {
 
         final ActorRef shard =
-            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new ShardContext()));
+            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -129,9 +129,9 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
         throws Throwable {
 
         final ActorRef shard =
-            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new ShardContext()));
+            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -159,9 +159,9 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
 
         final ActorRef shard =
-            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new ShardContext()));
+            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newWriteOnlyTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -192,9 +192,9 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
 
         final ActorRef shard =
-            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new ShardContext()));
+            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -230,9 +230,9 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
 
         final ActorRef shard =
-            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new ShardContext()));
+            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props, "testNegativeMergeTransactionReady");
@@ -263,9 +263,9 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
 
         final ActorRef shard =
-            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new ShardContext()));
+            getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
index 1dd824568a81820d21f50fd820d47eeef68c73e9..ff2ee08f94ee610afeef6a0f8d069d7adfe79952 100644 (file)
@@ -60,7 +60,7 @@ public class ShardTransactionTest extends AbstractActorTest {
         ShardIdentifier.builder().memberName("member-1")
             .shardName("inventory").type("config").build();
 
-    private ShardContext shardContext = new ShardContext();
+    private DatastoreContext datastoreContext = new DatastoreContext();
 
     @BeforeClass
     public static void staticSetup() {
@@ -71,9 +71,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveReadData() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject = getSystem().actorOf(props, "testReadData");
 
             new Within(duration("1 seconds")) {
@@ -114,9 +114,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveReadDataWhenDataNotFound() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props( store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject = getSystem().actorOf(props, "testReadDataWhenDataNotFound");
 
             new Within(duration("1 seconds")) {
@@ -158,9 +158,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveDataExistsPositive() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject = getSystem().actorOf(props, "testDataExistsPositive");
 
             new Within(duration("1 seconds")) {
@@ -201,9 +201,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveDataExistsNegative() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject = getSystem().actorOf(props, "testDataExistsNegative");
 
             new Within(duration("1 seconds")) {
@@ -279,9 +279,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveWriteData() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props(store.newWriteOnlyTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject =
                 getSystem().actorOf(props, "testWriteData");
 
@@ -320,9 +320,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveMergeData() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject =
                 getSystem().actorOf(props, "testMergeData");
 
@@ -362,9 +362,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveDeleteData() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props( store.newWriteOnlyTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject =
                 getSystem().actorOf(props, "testDeleteData");
 
@@ -402,9 +402,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveReadyTransaction() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props( store.newReadWriteTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject =
                 getSystem().actorOf(props, "testReadyTransaction");
 
@@ -441,9 +441,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveCloseTransaction() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject =
                 getSystem().actorOf(props, "testCloseTransaction");
 
@@ -492,9 +492,9 @@ public class ShardTransactionTest extends AbstractActorTest {
     @Test(expected=UnknownMessageException.class)
     public void testNegativePerformingWriteOperationOnReadTransaction() throws Exception {
         final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                Collections.EMPTY_MAP, new ShardContext()));
+                Collections.EMPTY_MAP, new DatastoreContext()));
         final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                testSchemaContext, shardContext);
+                testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
         final TestActorRef subject = TestActorRef.apply(props,getSystem());
 
         subject.receive(new DeleteData(TestModel.TEST_PATH).toSerializable(), ActorRef.noSender());
@@ -503,14 +503,14 @@ public class ShardTransactionTest extends AbstractActorTest {
     @Test
     public void testShardTransactionInactivity() {
 
-        shardContext = new ShardContext(InMemoryDOMDataStoreConfigProperties.getDefault(),
+        datastoreContext = new DatastoreContext(InMemoryDOMDataStoreConfigProperties.getDefault(),
                 Duration.create(500, TimeUnit.MILLISECONDS));
 
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                    Collections.EMPTY_MAP, new ShardContext()));
+                    Collections.EMPTY_MAP, new DatastoreContext()));
             final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                    testSchemaContext, shardContext);
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString());
             final ActorRef subject =
                 getSystem().actorOf(props, "testShardTransactionInactivity");
 
index 672166c4424c7ea0a8fd5c7ddd2e07b057e572b2..e39b9abd65a711e333f9c0315b25de2e3457266a 100644 (file)
@@ -13,6 +13,7 @@ package org.opendaylight.controller.cluster.datastore;
 import akka.actor.ActorRef;
 import akka.actor.Props;
 import akka.testkit.TestActorRef;
+import akka.util.Timeout;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListeningExecutorService;
@@ -63,7 +64,8 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
         ShardIdentifier.builder().memberName("member-1")
             .shardName("inventory").type("config").build();
 
-    private final ShardContext shardContext = new ShardContext();
+    private final DatastoreContext datastoreContext = new DatastoreContext();
+
 
     @BeforeClass
     public static void staticSetup() {
@@ -77,13 +79,13 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
     public void testNegativeAbortResultsInException() throws Exception {
 
         final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                Collections.EMPTY_MAP, shardContext));
+                Collections.EMPTY_MAP, datastoreContext));
         final DOMStoreThreePhaseCommitCohort mockCohort = Mockito
             .mock(DOMStoreThreePhaseCommitCohort.class);
         final CompositeModification mockComposite =
             Mockito.mock(CompositeModification.class);
         final Props props =
-            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite);
+            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ThreePhaseCommitCohort> subject = TestActorRef
             .create(getSystem(), props,
@@ -106,13 +108,13 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
     public void testNegativeCanCommitResultsInException() throws Exception {
 
         final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                Collections.EMPTY_MAP, shardContext));
+                Collections.EMPTY_MAP, datastoreContext));
         final DOMStoreThreePhaseCommitCohort mockCohort = Mockito
             .mock(DOMStoreThreePhaseCommitCohort.class);
         final CompositeModification mockComposite =
             Mockito.mock(CompositeModification.class);
         final Props props =
-            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite);
+            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ThreePhaseCommitCohort> subject = TestActorRef
             .create(getSystem(), props,
@@ -138,13 +140,13 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
     public void testNegativePreCommitResultsInException() throws Exception {
 
         final ActorRef shard = getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-                Collections.EMPTY_MAP, shardContext));
+                Collections.EMPTY_MAP, datastoreContext));
         final DOMStoreThreePhaseCommitCohort mockCohort = Mockito
             .mock(DOMStoreThreePhaseCommitCohort.class);
         final CompositeModification mockComposite =
             Mockito.mock(CompositeModification.class);
         final Props props =
-            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite);
+            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite,SHARD_IDENTIFIER.toString());
 
         final TestActorRef<ThreePhaseCommitCohort> subject = TestActorRef
             .create(getSystem(), props,
@@ -168,12 +170,12 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
     public void testNegativeCommitResultsInException() throws Exception {
 
         final TestActorRef<Shard> subject = TestActorRef.create(getSystem(),
-                Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, shardContext),
+                Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, datastoreContext),
                 "testNegativeCommitResultsInException");
 
         final ActorRef shardTransaction =
             getSystem().actorOf(ShardTransaction.props(store.newReadWriteTransaction(), subject,
-                    testSchemaContext, shardContext));
+                    testSchemaContext, datastoreContext,SHARD_IDENTIFIER.toString()));
 
         ShardTransactionMessages.WriteData writeData =
             ShardTransactionMessages.WriteData.newBuilder()
@@ -184,17 +186,17 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
 
             ).build();
 
+        Timeout askTimeout = new Timeout(ASK_RESULT_DURATION);
+
         //This is done so that Modification list is updated which is used during commit
-        Future future =
-            akka.pattern.Patterns.ask(shardTransaction, writeData, 3000);
+        Future<Object> future = akka.pattern.Patterns.ask(shardTransaction, writeData, askTimeout);
 
         //ready transaction creates the cohort so that we get into the
         //block where in commmit is done
         ShardTransactionMessages.ReadyTransaction readyTransaction =
             ShardTransactionMessages.ReadyTransaction.newBuilder().build();
 
-        future =
-            akka.pattern.Patterns.ask(shardTransaction, readyTransaction, 3000);
+        future = akka.pattern.Patterns.ask(shardTransaction, readyTransaction, askTimeout);
 
         //but when the message is sent it will have the MockCommit object
         //so that we can simulate throwing of exception
@@ -215,10 +217,7 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
         when(mockModification.toSerializable()).thenReturn(
             PersistentMessages.CompositeModification.newBuilder().build());
 
-        future =
-            akka.pattern.Patterns.ask(subject,
-                mockForwardCommitTransaction
-                , 3000);
+        future = akka.pattern.Patterns.ask(subject, mockForwardCommitTransaction, askTimeout);
         Await.result(future, ASK_RESULT_DURATION);
     }
 
index adb12b298e99260b6f33a6c309f3c6eb16ca78bb..1cd0f85fa1917057f77144f23009a7edb65c0150 100644 (file)
@@ -35,7 +35,6 @@ import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
 import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor;
 
 import scala.concurrent.Future;
-import scala.concurrent.duration.FiniteDuration;
 
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -93,12 +92,12 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
         }
 
         stubber.when(actorContext).executeRemoteOperationAsync(any(ActorSelection.class),
-                isA(requestType), any(FiniteDuration.class));
+                isA(requestType));
     }
 
     private void verifyCohortInvocations(int nCohorts, Class<?> requestType) {
         verify(actorContext, times(nCohorts)).executeRemoteOperationAsync(
-                any(ActorSelection.class), isA(requestType), any(FiniteDuration.class));
+                any(ActorSelection.class), isA(requestType));
     }
 
     private void propagateExecutionExceptionCause(ListenableFuture<?> future) throws Throwable {
index f69ae88ec873ed044ab40c36a63e6f0b68b9db67..e5392e025158704f44d152306aaa727b64d460e8 100644 (file)
@@ -56,8 +56,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
-import scala.concurrent.duration.FiniteDuration;
-
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -216,10 +214,6 @@ public class TransactionProxyTest extends AbstractActorTest {
         return getSystem().actorSelection(actorRef.path());
     }
 
-    private FiniteDuration anyDuration() {
-        return any(FiniteDuration.class);
-    }
-
     private CreateTransactionReply createTransactionReply(ActorRef actorRef){
         return CreateTransactionReply.newBuilder()
             .setTransactionActorPath(actorRef.path().toString())
@@ -232,7 +226,7 @@ public class TransactionProxyTest extends AbstractActorTest {
                 when(mockActorContext).actorSelection(actorRef.path().toString());
         doReturn(createTransactionReply(actorRef)).when(mockActorContext).
                 executeShardOperation(eq(DefaultShardStrategy.DEFAULT_SHARD),
-                        eqCreateTransaction(memberName, type), anyDuration());
+                        eqCreateTransaction(memberName, type));
         doReturn(actorRef.path().toString()).when(mockActorContext).resolvePath(
                 anyString(), eq(actorRef.path().toString()));
         doReturn(actorRef.path()).when(mockActorContext).actorFor(actorRef.path().toString());
@@ -259,7 +253,7 @@ public class TransactionProxyTest extends AbstractActorTest {
                 READ_ONLY);
 
         doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData(), anyDuration());
+                eq(actorSelection(actorRef)), eqReadData());
 
         Optional<NormalizedNode<?, ?>> readOptional = transactionProxy.read(
                 TestModel.TEST_PATH).get(5, TimeUnit.SECONDS);
@@ -269,7 +263,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(readDataReply(expectedNode)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData(), anyDuration());
+                eq(actorSelection(actorRef)), eqReadData());
 
         readOptional = transactionProxy.read(TestModel.TEST_PATH).get(5, TimeUnit.SECONDS);
 
@@ -283,7 +277,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         setupActorContextWithInitialCreateTransaction(READ_ONLY);
 
         doReturn(Futures.successful(new Object())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any(), anyDuration());
+                executeRemoteOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -296,7 +290,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         setupActorContextWithInitialCreateTransaction(READ_ONLY);
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any(), anyDuration());
+                executeRemoteOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -308,7 +302,7 @@ public class TransactionProxyTest extends AbstractActorTest {
             throws Throwable {
 
         doThrow(exToThrow).when(mockActorContext).executeShardOperation(
-                anyString(), any(), anyDuration());
+                anyString(), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -348,14 +342,13 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData(),
-                        anyDuration());
+                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData());
 
         doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData(), anyDuration());
+                eq(actorSelection(actorRef)), eqReadData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -368,7 +361,7 @@ public class TransactionProxyTest extends AbstractActorTest {
             propagateReadFailedExceptionCause(transactionProxy.read(TestModel.TEST_PATH));
         } finally {
             verify(mockActorContext, times(0)).executeRemoteOperationAsync(
-                    eq(actorSelection(actorRef)), eqReadData(), anyDuration());
+                    eq(actorSelection(actorRef)), eqReadData());
         }
     }
 
@@ -379,10 +372,10 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(expectedNode), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(expectedNode));
 
         doReturn(readDataReply(expectedNode)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData(), anyDuration());
+                eq(actorSelection(actorRef)), eqReadData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -414,14 +407,14 @@ public class TransactionProxyTest extends AbstractActorTest {
                 READ_ONLY);
 
         doReturn(dataExistsReply(false)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists(), anyDuration());
+                eq(actorSelection(actorRef)), eqDataExists());
 
         Boolean exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet();
 
         assertEquals("Exists response", false, exists);
 
         doReturn(dataExistsReply(true)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists(), anyDuration());
+                eq(actorSelection(actorRef)), eqDataExists());
 
         exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet();
 
@@ -443,7 +436,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         setupActorContextWithInitialCreateTransaction(READ_ONLY);
 
         doReturn(Futures.successful(new Object())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any(), anyDuration());
+                executeRemoteOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -456,7 +449,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         setupActorContextWithInitialCreateTransaction(READ_ONLY);
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any(), anyDuration());
+                executeRemoteOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -471,14 +464,13 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData(),
-                        anyDuration());
+                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData());
 
         doReturn(dataExistsReply(false)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists(), anyDuration());
+                eq(actorSelection(actorRef)), eqDataExists());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -491,7 +483,7 @@ public class TransactionProxyTest extends AbstractActorTest {
             propagateReadFailedExceptionCause(transactionProxy.exists(TestModel.TEST_PATH));
         } finally {
             verify(mockActorContext, times(0)).executeRemoteOperationAsync(
-                    eq(actorSelection(actorRef)), eqDataExists(), anyDuration());
+                    eq(actorSelection(actorRef)), eqDataExists());
         }
     }
 
@@ -502,10 +494,10 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         doReturn(dataExistsReply(true)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists(), anyDuration());
+                eq(actorSelection(actorRef)), eqDataExists());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -556,7 +548,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -564,7 +556,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         transactionProxy.write(TestModel.TEST_PATH, nodeToWrite);
 
         verify(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 WriteDataReply.SERIALIZABLE_CLASS);
@@ -599,7 +591,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -607,7 +599,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         transactionProxy.merge(TestModel.TEST_PATH, nodeToWrite);
 
         verify(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
 
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 MergeDataReply.SERIALIZABLE_CLASS);
@@ -618,7 +610,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY);
 
         doReturn(deleteDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDeleteData(), anyDuration());
+                eq(actorSelection(actorRef)), eqDeleteData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -626,7 +618,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         transactionProxy.delete(TestModel.TEST_PATH);
 
         verify(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDeleteData(), anyDuration());
+                eq(actorSelection(actorRef)), eqDeleteData());
 
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 DeleteDataReply.SERIALIZABLE_CLASS);
@@ -665,13 +657,13 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData(), anyDuration());
+                eq(actorSelection(actorRef)), eqReadData());
 
         doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         doReturn(readyTxReply(actorRef.path())).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS), anyDuration());
+                eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -700,14 +692,13 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqWriteData(nodeToWrite),
-                        anyDuration());
+                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         doReturn(readyTxReply(actorRef.path())).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS), anyDuration());
+                eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -736,11 +727,11 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
                 executeRemoteOperationAsync(eq(actorSelection(actorRef)),
-                        isA(ReadyTransaction.SERIALIZABLE_CLASS), anyDuration());
+                        isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -763,7 +754,7 @@ public class TransactionProxyTest extends AbstractActorTest {
     public void testReadyWithInitialCreateTransactionFailure() throws Exception {
 
         doThrow(new PrimaryNotFoundException("mock")).when(mockActorContext).executeShardOperation(
-                anyString(), any(), anyDuration());
+                anyString(), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -793,11 +784,11 @@ public class TransactionProxyTest extends AbstractActorTest {
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
         doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite), anyDuration());
+                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
 
         doReturn(Futures.successful(new Object())).when(mockActorContext).
                 executeRemoteOperationAsync(eq(actorSelection(actorRef)),
-                        isA(ReadyTransaction.SERIALIZABLE_CLASS), anyDuration());
+                        isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -830,7 +821,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE);
 
         doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData(), anyDuration());
+                eq(actorSelection(actorRef)), eqReadData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
index 41adcc55b188296f899b1569e98276906b233c1e..c4d0b85fb54546faa5e0667e58e472d549d5836f 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard;
 
 import org.junit.After;
@@ -86,7 +93,69 @@ public class ShardStatsTest {
         Object attribute =
             mbeanServer.getAttribute(testMBeanName, "FailedTransactionsCount");
         Assert.assertEquals((Long) attribute, (Long) 2L);
+    }
+
+    @Test
+    public void testGetAbortTransactionsCount() throws Exception {
+        //let us increment AbortTransactions count and then check
+        shardStats.incrementAbortTransactionsCount();
+        shardStats.incrementAbortTransactionsCount();
+
+
+        //now let us get from MBeanServer what is the transaction count.
+        Object attribute =
+            mbeanServer.getAttribute(testMBeanName, "AbortTransactionsCount");
+        Assert.assertEquals((Long) attribute, (Long) 2L);
+    }
+
+    @Test
+    public void testGetFailedReadTransactionsCount() throws Exception {
+        //let us increment FailedReadTransactions count and then check
+        shardStats.incrementFailedReadTransactionsCount();
+        shardStats.incrementFailedReadTransactionsCount();
+
+
+        //now let us get from MBeanServer what is the transaction count.
+        Object attribute =
+            mbeanServer.getAttribute(testMBeanName, "FailedReadTransactionsCount");
+        Assert.assertEquals((Long) attribute, (Long) 2L);
+    }
+
+    @Test
+    public void testResetTransactionCounters() throws Exception {
+
+        //let us increment committed transactions count and then check
+        shardStats.incrementCommittedTransactionCount();
+        shardStats.incrementCommittedTransactionCount();
+        shardStats.incrementCommittedTransactionCount();
+
+        //now let us get from MBeanServer what is the transaction count.
+        Object attribute = mbeanServer.getAttribute(testMBeanName,
+            "CommittedTransactionsCount");
+        Assert.assertEquals((Long) attribute, (Long) 3L);
+
+        //let us increment FailedReadTransactions count and then check
+        shardStats.incrementFailedReadTransactionsCount();
+        shardStats.incrementFailedReadTransactionsCount();
+
+
+        //now let us get from MBeanServer what is the transaction count.
+        attribute =
+            mbeanServer.getAttribute(testMBeanName, "FailedReadTransactionsCount");
+        Assert.assertEquals((Long) attribute, (Long) 2L);
+
+
+        //here we will reset the counters and check the above ones are 0 after reset
+        mbeanServer.invoke(testMBeanName, "resetTransactionCounters", null, null);
+
+        //now let us get from MBeanServer what is the transaction count.
+        attribute = mbeanServer.getAttribute(testMBeanName,
+            "CommittedTransactionsCount");
+        Assert.assertEquals((Long) attribute, (Long) 0L);
 
+        attribute =
+            mbeanServer.getAttribute(testMBeanName, "FailedReadTransactionsCount");
+        Assert.assertEquals((Long) attribute, (Long) 0L);
 
 
     }
index fda9ccdfdbbd44dda363c92b842d246e389466bb..5d8fb8393d6c4fd773a0a94b6fd156ac02fe1c14 100644 (file)
@@ -117,7 +117,7 @@ public class ActorContextTest extends AbstractActorTest{
                         new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
                             mock(Configuration.class));
 
-                    Object out = actorContext.executeLocalShardOperation("default", "hello", duration("1 seconds"));
+                    Object out = actorContext.executeLocalShardOperation("default", "hello");
 
                     assertEquals("hello", out);
 
@@ -144,7 +144,7 @@ public class ActorContextTest extends AbstractActorTest{
                         new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
                             mock(Configuration.class));
 
-                    Object out = actorContext.executeLocalShardOperation("default", "hello", duration("1 seconds"));
+                    Object out = actorContext.executeLocalShardOperation("default", "hello");
 
                     assertNull(out);
 
@@ -232,7 +232,7 @@ public class ActorContextTest extends AbstractActorTest{
 
                     ActorSelection actor = actorContext.actorSelection(shardActorRef.path());
 
-                    Object out = actorContext.executeRemoteOperation(actor, "hello", duration("3 seconds"));
+                    Object out = actorContext.executeRemoteOperation(actor, "hello");
 
                     assertEquals("hello", out);
 
@@ -261,8 +261,7 @@ public class ActorContextTest extends AbstractActorTest{
 
                     ActorSelection actor = actorContext.actorSelection(shardActorRef.path());
 
-                    Future<Object> future = actorContext.executeRemoteOperationAsync(actor, "hello",
-                            Duration.create(3, TimeUnit.SECONDS));
+                    Future<Object> future = actorContext.executeRemoteOperationAsync(actor, "hello");
 
                     try {
                         Object result = Await.result(future, Duration.create(3, TimeUnit.SECONDS));
index b19fd3a5290b2c8df92917403d7a501bcf79bfcf..8fa3a17f901541f79be1ec45a373ebe097ba69a1 100644 (file)
@@ -12,7 +12,6 @@ import static org.junit.Assert.assertNotNull;
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
 import akka.actor.ActorSystem;
-import scala.concurrent.duration.FiniteDuration;
 
 public class MockActorContext extends ActorContext {
 
@@ -33,12 +32,12 @@ public class MockActorContext extends ActorContext {
 
 
     @Override public Object executeShardOperation(String shardName,
-        Object message, FiniteDuration duration) {
+        Object message) {
         return executeShardOperationResponse;
     }
 
     @Override public Object executeRemoteOperation(ActorSelection actor,
-        Object message, FiniteDuration duration) {
+        Object message) {
         return executeRemoteOperationResponse;
     }
 
@@ -76,13 +75,13 @@ public class MockActorContext extends ActorContext {
 
     @Override
     public Object executeLocalOperation(ActorRef actor,
-        Object message, FiniteDuration duration) {
+        Object message) {
         return this.executeLocalOperationResponse;
     }
 
     @Override
     public Object executeLocalShardOperation(String shardName,
-        Object message, FiniteDuration duration) {
+        Object message) {
         return this.executeLocalShardOperationResponse;
     }
 }
index 939096e7f306c7c6d3f0b131fa0880f6374fa274..4ddba2f1b9d773b3c4783d3e401fa7df43d32a0e 100644 (file)
@@ -21,8 +21,7 @@ public class TestUtils {
         ActorContext testContext = new ActorContext(actorSystem, actorSystem.actorOf(
             Props.create(DoNothingActor.class)), new MockClusterWrapper(), new MockConfiguration());
         Object messages = testContext
-            .executeLocalOperation(actorRef, "messages",
-                ActorContext.ASK_DURATION);
+            .executeLocalOperation(actorRef, "messages");
 
         Assert.assertNotNull(messages);
 
index 27b0374bacbaa6b224c52ceaf7d33a83ffa554fb..6851b1b72ce39d4c011cb0771b95014bb31ade32 100644 (file)
@@ -14,3 +14,8 @@ akka {
         }
     }
 }
+bounded-mailbox {
+  mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+  mailbox-capacity = 1000
+  mailbox-push-timeout-time = 100ms
+}
index 8664e8910b46bda523951f22961d59c13cbaec42..b423bbd0e5c644c147a69398a65da0a564c985a1 100644 (file)
@@ -7,11 +7,13 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.dom.impl;
 
-import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
+
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitDeadlockException;
+import org.opendaylight.controller.md.sal.common.util.jmx.ThreadExecutorStatsMXBeanImpl;
 import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.broker.impl.jmx.CommitStatsMXBeanImpl;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService;
@@ -24,6 +26,8 @@ import com.google.common.collect.ImmutableMap;
 public final class DomInmemoryDataBrokerModule extends
         org.opendaylight.controller.config.yang.md.sal.dom.impl.AbstractDomInmemoryDataBrokerModule {
 
+    private static final String JMX_BEAN_TYPE = "DOMDataBroker";
+
     public DomInmemoryDataBrokerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
             final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
@@ -78,7 +82,7 @@ public final class DomInmemoryDataBrokerModule extends
          * nothing on success. The executor queue capacity is bounded and, if the capacity is
          * reached, subsequent submitted tasks will block the caller.
          */
-        Executor listenableFutureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(
+        ExecutorService listenableFutureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(
                 getMaxDataBrokerFutureCallbackPoolSize(), getMaxDataBrokerFutureCallbackQueueSize(),
                 "CommitFutures");
 
@@ -87,6 +91,29 @@ public final class DomInmemoryDataBrokerModule extends
                     TransactionCommitDeadlockException.DEADLOCK_EXECUTOR_FUNCTION,
                     listenableFutureExecutor));
 
+        final CommitStatsMXBeanImpl commitStatsMXBean = new CommitStatsMXBeanImpl(
+                newDataBroker.getCommitStatsTracker(), JMX_BEAN_TYPE);
+        commitStatsMXBean.registerMBean();
+
+        final ThreadExecutorStatsMXBeanImpl commitExecutorStatsMXBean =
+                new ThreadExecutorStatsMXBeanImpl(commitExecutor, "CommitExecutorStats",
+                        JMX_BEAN_TYPE, null);
+        commitExecutorStatsMXBean.registerMBean();
+
+        final ThreadExecutorStatsMXBeanImpl commitFutureStatsMXBean =
+                new ThreadExecutorStatsMXBeanImpl(listenableFutureExecutor,
+                        "CommitFutureExecutorStats", JMX_BEAN_TYPE, null);
+        commitFutureStatsMXBean.registerMBean();
+
+        newDataBroker.setCloseable(new AutoCloseable() {
+            @Override
+            public void close() {
+                commitStatsMXBean.unregisterMBean();
+                commitExecutorStatsMXBean.unregisterMBean();
+                commitFutureStatsMXBean.unregisterMBean();
+            }
+        });
+
         return newDataBroker;
     }
 }
index d1b9a8f6005097ccc463d87efe2a52d0e3911b4c..d63d6cbe3674fb44e9131e8cbf99dc52453e5ae5 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,6 +41,7 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
     private final DOMDataCommitCoordinatorImpl coordinator;
     private final AtomicLong txNum = new AtomicLong();
     private final AtomicLong chainNum = new AtomicLong();
+    private volatile AutoCloseable closeable;
 
     public DOMDataBrokerImpl(final ImmutableMap<LogicalDatastoreType, DOMStore> datastores,
             final ListeningExecutorService executor) {
@@ -47,6 +49,27 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
         this.coordinator = new DOMDataCommitCoordinatorImpl(executor);
     }
 
+    public void setCloseable(AutoCloseable closeable) {
+        this.closeable = closeable;
+    }
+
+    public DurationStatsTracker getCommitStatsTracker() {
+        return coordinator.getCommitStatsTracker();
+    }
+
+    @Override
+    public void close() {
+        super.close();
+
+        if(closeable != null) {
+            try {
+                closeable.close();
+            } catch(Exception e) {
+                LOG.debug("Error closing instance", e);
+            }
+        }
+    }
+
     @Override
     protected Object newTransactionIdentifier() {
         return "DOM-" + txNum.getAndIncrement();
@@ -82,5 +105,4 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
         LOG.debug("Transaction: {} submitted with cohorts {}.", transaction.getIdentifier(), cohorts);
         return coordinator.submit(transaction, cohorts, Optional.<DOMDataCommitErrorListener> absent());
     }
-
 }
index 521e2d0e731af06ac972ce2cce28f75a347ba490..3fde8d360f8af6df8cb0bcd705a9e3289d9fd35e 100644 (file)
@@ -16,6 +16,7 @@ import javax.annotation.concurrent.GuardedBy;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
 import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -69,6 +70,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
 
     private final ListeningExecutorService executor;
 
+    private final DurationStatsTracker commitStatsTracker = new DurationStatsTracker();
+
     /**
      *
      * Construct DOMDataCommitCoordinator which uses supplied executor to
@@ -80,6 +83,10 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
         this.executor = Preconditions.checkNotNull(executor, "executor must not be null.");
     }
 
+    public DurationStatsTracker getCommitStatsTracker() {
+        return commitStatsTracker;
+    }
+
     @Override
     public CheckedFuture<Void,TransactionCommitFailedException> submit(final DOMDataWriteTransaction transaction,
             final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final Optional<DOMDataCommitErrorListener> listener) {
@@ -90,7 +97,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
 
         ListenableFuture<Void> commitFuture = null;
         try {
-            commitFuture = executor.submit(new CommitCoordinationTask(transaction, cohorts, listener));
+            commitFuture = executor.submit(new CommitCoordinationTask(transaction, cohorts,
+                    listener, commitStatsTracker));
         } catch(RejectedExecutionException e) {
             LOG.error("The commit executor's queue is full - submit task was rejected. \n" +
                       executor, e);
@@ -154,21 +162,25 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
 
         private final DOMDataWriteTransaction tx;
         private final Iterable<DOMStoreThreePhaseCommitCohort> cohorts;
+        private final DurationStatsTracker commitStatTracker;
 
         @GuardedBy("this")
         private CommitPhase currentPhase;
 
         public CommitCoordinationTask(final DOMDataWriteTransaction transaction,
                 final Iterable<DOMStoreThreePhaseCommitCohort> cohorts,
-                final Optional<DOMDataCommitErrorListener> listener) {
+                final Optional<DOMDataCommitErrorListener> listener,
+                final DurationStatsTracker commitStatTracker) {
             this.tx = Preconditions.checkNotNull(transaction, "transaction must not be null");
             this.cohorts = Preconditions.checkNotNull(cohorts, "cohorts must not be null");
             this.currentPhase = CommitPhase.SUBMITTED;
+            this.commitStatTracker = commitStatTracker;
         }
 
         @Override
         public Void call() throws TransactionCommitFailedException {
 
+            long startTime = System.nanoTime();
             try {
                 canCommitBlocking();
                 preCommitBlocking();
@@ -178,6 +190,10 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
                 LOG.warn("Tx: {} Error during phase {}, starting Abort", tx.getIdentifier(), currentPhase, e);
                 abortBlocking(e);
                 throw e;
+            } finally {
+                if(commitStatTracker != null) {
+                    commitStatTracker.addDuration(System.nanoTime() - startTime);
+                }
             }
         }
 
index b9504e72685f92f401173030af658d34b1982dcf..1c12d20504702eb7bf551922463bac74535f42c9 100644 (file)
@@ -62,12 +62,18 @@ abstract class TranslatingListenerInvoker implements AutoCloseable, DOMDataChang
         }
     }
 
+    @Override
+    public String toString() {
+        return getDelegate().getClass().getName();
+    }
+
     static final class TranslatingConfigListenerInvoker extends TranslatingListenerInvoker {
 
         public TranslatingConfigListenerInvoker(final DataChangeListener listener, final DataNormalizer normalizer) {
             super(listener, normalizer);
         }
 
+        @Override
         DataChangeEvent<YangInstanceIdentifier, CompositeNode> getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
             return TranslatingDataChangeEvent.createConfiguration(normalizedChange, normalizer);
         }
@@ -85,6 +91,7 @@ abstract class TranslatingListenerInvoker implements AutoCloseable, DOMDataChang
             super(listener, normalizer);
         }
 
+        @Override
         DataChangeEvent<YangInstanceIdentifier, CompositeNode> getLegacyEvent(final DataNormalizer normalizer, final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedChange) {
             return TranslatingDataChangeEvent.createOperational(normalizedChange, normalizer);
         }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBean.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBean.java
new file mode 100644 (file)
index 0000000..40dc30e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.dom.broker.impl.jmx;
+
+/**
+ * MXBean interface for retrieving write Tx commit statistics.
+ *
+ * @author Thomas Pantelis
+ */
+public interface CommitStatsMXBean {
+
+    /**
+     * Returns the total number of commits that have occurred.
+     */
+    long getTotalCommits();
+
+    /**
+     * Returns a string representing the time duration of the longest commit, in the appropriate
+     * scaled units, along with the date/time that it occurred.
+     */
+    String getLongestCommitTime();
+
+    /**
+     * Returns a string representing the time duration of the shortest commit, in the appropriate
+     * scaled units, along with the date/time that it occurred.
+     */
+    String getShortestCommitTime();
+
+    /**
+     * Returns a string representing average commit time duration, in the appropriate
+     * scaled units.
+     */
+    String getAverageCommitTime();
+
+    /**
+     * Clears the current stats to their defaults.
+     */
+    void clearStats();
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java
new file mode 100644 (file)
index 0000000..f67f6b0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.dom.broker.impl.jmx;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.common.util.jmx.AbstractMXBean;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
+
+/**
+ * Implementation of the CommitStatsMXBean interface.
+ *
+ * @author Thomas Pantelis
+ */
+public class CommitStatsMXBeanImpl extends AbstractMXBean implements CommitStatsMXBean {
+
+    private final DurationStatsTracker commitStatsTracker;
+
+    /**
+     * Constructor.
+     *
+     * @param commitStatsTracker the DurationStatsTracker used to obtain the stats.
+     * @param mBeanType mBeanType Used as the <code>type</code> property in the bean's ObjectName.
+     */
+    public CommitStatsMXBeanImpl(@Nonnull DurationStatsTracker commitStatsTracker,
+            @Nonnull String mBeanType) {
+        super("CommitStats", mBeanType, null);
+        this.commitStatsTracker = commitStatsTracker;
+    }
+
+    @Override
+    public long getTotalCommits() {
+        return commitStatsTracker.getTotalDurations();
+    }
+
+    @Override
+    public String getLongestCommitTime() {
+        return commitStatsTracker.getDisplayableLongestDuration();
+    }
+
+    @Override
+    public String getShortestCommitTime() {
+        return commitStatsTracker.getDisplayableShortestDuration();
+    }
+
+    @Override
+    public String getAverageCommitTime() {
+        return commitStatsTracker.getDisplayableAverageDuration();
+    }
+
+    @Override
+    public void clearStats() {
+        commitStatsTracker.reset();
+    }
+}
index 82637327f6b10d719c04e4fa04ad6a7b53b2dafe..c4418c7911a79b6d786c7a47a638e87ceffa59bc 100644 (file)
@@ -10,6 +10,10 @@ package org.opendaylight.controller.sal.dom.broker;
 import static com.google.common.base.Preconditions.checkState;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -20,7 +24,7 @@ import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
@@ -36,10 +40,6 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
 public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService, ServiceTrackerCustomizer<SchemaContextListener, SchemaContextListener>, AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class);
 
@@ -71,7 +71,11 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi
 
     @VisibleForTesting
     public static synchronized void destroyInstance() {
-        instance = null;
+        try {
+            instance.close();
+        } finally {
+            instance = null;
+        }
     }
 
     public BundleContext getContext() {
@@ -124,16 +128,18 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi
     }
 
     @Override
-    public void close() throws Exception {
+    public void close() {
         if (bundleTracker != null) {
             bundleTracker.close();
         }
         if (listenerTracker != null) {
             listenerTracker.close();
         }
-        // FIXME: Add listeners.close();
-    }
 
+        for (ListenerRegistration<SchemaContextListener> l : listeners.getListeners()) {
+            l.close();
+        }
+    }
 
     private synchronized void updateContext(final SchemaContext snapshot) {
         Object[] services = listenerTracker.getServices();
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImplTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImplTest.java
new file mode 100644 (file)
index 0000000..d796930
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.dom.broker.impl.jmx;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.util.DurationStatsTracker;
+
+/**
+ * Unit tests for CommitStatsMXBeanImpl.
+ *
+ * @author Thomas Pantelis
+ */
+public class CommitStatsMXBeanImplTest {
+
+    @Test
+    public void test() {
+
+        DurationStatsTracker commitStatsTracker = new DurationStatsTracker();
+        CommitStatsMXBeanImpl bean =
+                new CommitStatsMXBeanImpl(commitStatsTracker, "Test");
+
+        commitStatsTracker.addDuration(100);
+
+        String prefix = "100.0 ns";
+        assertEquals("getTotalCommits", 1L, bean.getTotalCommits());
+        assertEquals("getLongestCommitTime starts with \"" + prefix + "\"", true,
+                     bean.getLongestCommitTime().startsWith("100.0 ns"));
+        assertEquals("getShortestCommitTime starts with \"" + prefix + "\"", true,
+                     bean.getShortestCommitTime().startsWith(prefix));
+        assertEquals("getAverageCommitTime starts with \"" + prefix + "\"", true,
+                     bean.getAverageCommitTime().startsWith(prefix));
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/statistics/DOMStoreStatsTracker.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/statistics/DOMStoreStatsTracker.java
new file mode 100644 (file)
index 0000000..12713b2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.core.spi.data.statistics;
+
+import java.util.concurrent.ExecutorService;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+
+/**
+ * Interface for a class that tracks statistics for a data store.
+ *
+ * @author Thomas Pantelis
+ */
+public interface DOMStoreStatsTracker {
+
+    /**
+     * Sets the executor used for DataChangeListener notifications.
+     *
+     * @param dclExecutor the executor
+     */
+    void setDataChangeListenerExecutor( @Nonnull ExecutorService dclExecutor );
+
+    /**
+     * Sets the executor used internally by the data store.
+     *
+     * @param dsExecutor the executor
+     */
+    void setDataStoreExecutor( @Nonnull ExecutorService dsExecutor );
+
+    /**
+     * Sets the QueuedNotificationManager use for DataChangeListener notifications,
+     *
+     * @param manager the manager
+     */
+    void setNotificationManager( @Nonnull QueuedNotificationManager<?, ?> manager );
+}
index fd1627c6f994677abe043f767519fbb78e2d5eeb..b98844ba641f6e7f585c3c6b687c56d55161933c 100644 (file)
@@ -1,7 +1,9 @@
 package org.opendaylight.controller.config.yang.inmemory_datastore_provider;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
+import org.opendaylight.controller.md.sal.dom.store.impl.jmx.InMemoryDataStoreStats;
 
 public class InMemoryConfigDataStoreProviderModule extends org.opendaylight.controller.config.yang.inmemory_datastore_provider.AbstractInMemoryConfigDataStoreProviderModule {
 
@@ -20,9 +22,19 @@ public class InMemoryConfigDataStoreProviderModule extends org.opendaylight.cont
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return InMemoryDOMDataStoreFactory.create("DOM-CFG", getSchemaServiceDependency(),
+
+        InMemoryDOMDataStore dataStore = InMemoryDOMDataStoreFactory.create(
+                "DOM-CFG", getSchemaServiceDependency(),
                 InMemoryDOMDataStoreConfigProperties.create(getMaxDataChangeExecutorPoolSize(),
-                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize()));
+                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize(),
+                        getMaxDataStoreExecutorQueueSize()));
+
+        InMemoryDataStoreStats statsBean = new InMemoryDataStoreStats("InMemoryConfigDataStore",
+                dataStore.getDataChangeListenerNotificationManager(), dataStore.getDomStoreExecutor());
+
+        dataStore.setCloseable(statsBean);
+
+        return dataStore;
     }
 
 }
index 6596acb4e1bbb8caf9336a7e31cad98b521b0948..4532452c65e32521dece928f5b20f00310f3c358 100644 (file)
@@ -1,7 +1,9 @@
 package org.opendaylight.controller.config.yang.inmemory_datastore_provider;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
+import org.opendaylight.controller.md.sal.dom.store.impl.jmx.InMemoryDataStoreStats;
 
 public class InMemoryOperationalDataStoreProviderModule extends org.opendaylight.controller.config.yang.inmemory_datastore_provider.AbstractInMemoryOperationalDataStoreProviderModule {
 
@@ -20,9 +22,17 @@ public class InMemoryOperationalDataStoreProviderModule extends org.opendaylight
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return InMemoryDOMDataStoreFactory.create("DOM-OPER", getSchemaServiceDependency(),
+        InMemoryDOMDataStore dataStore = InMemoryDOMDataStoreFactory.create("DOM-OPER", getSchemaServiceDependency(),
                 InMemoryDOMDataStoreConfigProperties.create(getMaxDataChangeExecutorPoolSize(),
-                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize()));
-    }
+                        getMaxDataChangeExecutorQueueSize(), getMaxDataChangeListenerQueueSize(),
+                        getMaxDataStoreExecutorQueueSize()));
+
+
+        InMemoryDataStoreStats statsBean = new InMemoryDataStoreStats("InMemoryOperationalDataStore",
+                dataStore.getDataChangeListenerNotificationManager(), dataStore.getDomStoreExecutor());
 
+        dataStore.setCloseable(statsBean);
+
+        return dataStore;
+    }
 }
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChangeListenerNotifyTask.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChangeListenerNotifyTask.java
deleted file mode 100644 (file)
index 536cfa0..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.sal.dom.store.impl;
-
-import com.google.common.base.Preconditions;
-
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.yangtools.util.concurrent.NotificationManager;
-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;
-
-class ChangeListenerNotifyTask implements Runnable {
-    private static final Logger LOG = LoggerFactory.getLogger(ChangeListenerNotifyTask.class);
-
-    @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr;
-    private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event;
-    private final DataChangeListenerRegistration<?> listener;
-
-    @SuppressWarnings("rawtypes")
-    public ChangeListenerNotifyTask(final DataChangeListenerRegistration<?> listener,
-            final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event,
-            final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
-        this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
-        this.listener = Preconditions.checkNotNull(listener);
-        this.event = Preconditions.checkNotNull(event);
-    }
-
-    @Override
-    public void run() {
-        final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> l = listener.getInstance();
-        if (l == null) {
-            LOG.trace("Skipping event delivery to unregistered listener {}", l);
-            return;
-        }
-        LOG.trace("Listener {} event {}", l, event);
-
-        // FIXME: Yo dawg I heard you like queues, so this was queued to be queued
-        notificationMgr.submitNotification(l, event);
-    }
-
-    @Override
-    public String toString() {
-        return "ChangeListenerNotifyTask [listener=" + listener + ", event=" + event + "]";
-    }
-}
index 7ad3b8201e182cff9b3820a9e029f697e4cdb950..476356a19e79113b0b0121662b8842610757d12f 100644 (file)
@@ -7,30 +7,29 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.annotation.concurrent.GuardedBy;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
-import org.opendaylight.yangtools.util.ExecutorServiceUtil;
-import org.opendaylight.yangtools.util.concurrent.NotificationManager;
-import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
-import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
@@ -40,22 +39,23 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.ExecutorServiceUtil;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager.Invoker;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.concurrent.GuardedBy;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import static com.google.common.base.Preconditions.checkState;
-
 /**
  * In-memory DOM Data Store
  *
@@ -68,18 +68,17 @@ import static com.google.common.base.Preconditions.checkState;
 public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, SchemaContextListener,
         TransactionReadyPrototype,AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class);
+    private static final ListenableFuture<Void> SUCCESSFUL_FUTURE = Futures.immediateFuture(null);
 
-    @SuppressWarnings("rawtypes")
-    private static final QueuedNotificationManager.Invoker<AsyncDataChangeListener,
-                                       AsyncDataChangeEvent> DCL_NOTIFICATION_MGR_INVOKER =
-            new QueuedNotificationManager.Invoker<AsyncDataChangeListener,
-                                                  AsyncDataChangeEvent>() {
-
-                @SuppressWarnings("unchecked")
+    private static final Invoker<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> DCL_NOTIFICATION_MGR_INVOKER =
+            new Invoker<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent>() {
                 @Override
-                public void invokeListener( AsyncDataChangeListener listener,
-                                            AsyncDataChangeEvent notification ) {
-                    listener.onDataChanged(notification);
+                public void invokeListener(final DataChangeListenerRegistration<?> listener,
+                                           final DOMImmutableDataChangeEvent notification ) {
+                    final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> inst = listener.getInstance();
+                    if (inst != null) {
+                        inst.onDataChanged(notification);
+                    }
                 }
             };
 
@@ -88,24 +87,26 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     private final AtomicLong txCounter = new AtomicLong(0);
     private final ListeningExecutorService listeningExecutor;
 
-    @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent>
-                                                              dataChangeListenerNotificationManager;
+    private final QueuedNotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> dataChangeListenerNotificationManager;
     private final ExecutorService dataChangeListenerExecutor;
 
+    private final ExecutorService domStoreExecutor;
+
     private final String name;
 
-    public InMemoryDOMDataStore(final String name, final ListeningExecutorService listeningExecutor,
+    private volatile AutoCloseable closeable;
+
+    public InMemoryDOMDataStore(final String name, final ExecutorService domStoreExecutor,
             final ExecutorService dataChangeListenerExecutor) {
-        this(name, listeningExecutor, dataChangeListenerExecutor,
-                InMemoryDOMDataStoreConfigProperties.DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE);
+        this(name, domStoreExecutor, dataChangeListenerExecutor,
+             InMemoryDOMDataStoreConfigProperties.DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE);
     }
 
-    public InMemoryDOMDataStore(final String name, final ListeningExecutorService listeningExecutor,
-            final ExecutorService dataChangeListenerExecutor, int maxDataChangeListenerQueueSize) {
+    public InMemoryDOMDataStore(final String name, final ExecutorService domStoreExecutor,
+            final ExecutorService dataChangeListenerExecutor, final int maxDataChangeListenerQueueSize) {
         this.name = Preconditions.checkNotNull(name);
-        this.listeningExecutor = Preconditions.checkNotNull(listeningExecutor);
-
+        this.domStoreExecutor = Preconditions.checkNotNull(domStoreExecutor);
+        this.listeningExecutor = MoreExecutors.listeningDecorator(this.domStoreExecutor);
         this.dataChangeListenerExecutor = Preconditions.checkNotNull(dataChangeListenerExecutor);
 
         dataChangeListenerNotificationManager =
@@ -114,6 +115,18 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                         "DataChangeListenerQueueMgr");
     }
 
+    public void setCloseable(AutoCloseable closeable) {
+        this.closeable = closeable;
+    }
+
+    public QueuedNotificationManager<?, ?> getDataChangeListenerNotificationManager() {
+        return dataChangeListenerNotificationManager;
+    }
+
+    public ExecutorService getDomStoreExecutor() {
+        return domStoreExecutor;
+    }
+
     @Override
     public final String getIdentifier() {
         return name;
@@ -148,7 +161,16 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
     public void close() {
         ExecutorServiceUtil.tryGracefulShutdown(listeningExecutor, 30, TimeUnit.SECONDS);
         ExecutorServiceUtil.tryGracefulShutdown(dataChangeListenerExecutor, 30, TimeUnit.SECONDS);
+
+        if(closeable != null) {
+            try {
+                closeable.close();
+            } catch(Exception e) {
+                LOG.debug("Error closing instance", e);
+            }
+        }
     }
+
     @Override
     public <L extends AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(
             final YangInstanceIdentifier path, final L listener, final DataChangeScope scope) {
@@ -175,8 +197,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                         .addCreated(path, data) //
                         .build();
 
-                new ChangeListenerNotifyTask(reg, event,
-                        dataChangeListenerNotificationManager).run();
+                dataChangeListenerNotificationManager.submitNotification(reg, event);
             }
         }
 
@@ -277,7 +298,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
         }
 
         public synchronized void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) {
-            // If commited transaction is latestOutstandingTx we clear
+            // If committed transaction is latestOutstandingTx we clear
             // latestOutstandingTx
             // field in order to base new transactions on Datastore Data Tree
             // directly.
@@ -379,8 +400,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                 @Override
                 public Void call() {
                     candidate = dataTree.prepare(modification);
-                    listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree,
-                            dataChangeListenerNotificationManager);
+                    listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree);
                     return null;
                 }
             });
@@ -389,7 +409,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
         @Override
         public ListenableFuture<Void> abort() {
             candidate = null;
-            return Futures.immediateFuture(null);
+            return SUCCESSFUL_FUTURE;
         }
 
         @Override
@@ -402,14 +422,10 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
              */
             synchronized (this) {
                 dataTree.commit(candidate);
-
-                for (ChangeListenerNotifyTask task : listenerResolver.call()) {
-                    LOG.trace("Scheduling invocation of listeners: {}", task);
-                    task.run();
-                }
+                listenerResolver.resolve(dataChangeListenerNotificationManager);
             }
 
-            return Futures.immediateFuture(null);
+            return SUCCESSFUL_FUTURE;
         }
     }
 }
index 6e451ba12b20241d97c2826dce55d3870de0b9cb..be89d53a69b2b99b442c0820781959f30832666f 100644 (file)
@@ -20,15 +20,18 @@ public class InMemoryDOMDataStoreConfigProperties {
     public static final int DEFAULT_MAX_DATA_CHANGE_EXECUTOR_QUEUE_SIZE = 1000;
     public static final int DEFAULT_MAX_DATA_CHANGE_EXECUTOR_POOL_SIZE = 20;
     public static final int DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE = 1000;
+    public static final int DEFAULT_MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE = 5000;
 
     private static final InMemoryDOMDataStoreConfigProperties DEFAULT =
             create(DEFAULT_MAX_DATA_CHANGE_EXECUTOR_POOL_SIZE,
                     DEFAULT_MAX_DATA_CHANGE_EXECUTOR_QUEUE_SIZE,
-                    DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE);
+                    DEFAULT_MAX_DATA_CHANGE_LISTENER_QUEUE_SIZE,
+                    DEFAULT_MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE);
 
     private final int maxDataChangeExecutorQueueSize;
     private final int maxDataChangeExecutorPoolSize;
     private final int maxDataChangeListenerQueueSize;
+    private final int maxDataStoreExecutorQueueSize;
 
     /**
      * Constructs an instance with the given property values.
@@ -39,11 +42,22 @@ public class InMemoryDOMDataStoreConfigProperties {
      *            maximum queue size for the data change notification executor.
      * @param maxDataChangeListenerQueueSize
      *            maximum queue size for the data change listeners.
+     * @param maxDataStoreExecutorQueueSize
+     *            maximum queue size for the data store executor.
      */
+    public static InMemoryDOMDataStoreConfigProperties create(int maxDataChangeExecutorPoolSize,
+            int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize,
+            int maxDataStoreExecutorQueueSize) {
+        return new InMemoryDOMDataStoreConfigProperties(maxDataChangeExecutorPoolSize,
+                maxDataChangeExecutorQueueSize, maxDataChangeListenerQueueSize,
+                maxDataStoreExecutorQueueSize);
+    }
+
     public static InMemoryDOMDataStoreConfigProperties create(int maxDataChangeExecutorPoolSize,
             int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize) {
         return new InMemoryDOMDataStoreConfigProperties(maxDataChangeExecutorPoolSize,
-                maxDataChangeExecutorQueueSize, maxDataChangeListenerQueueSize);
+                maxDataChangeExecutorQueueSize, maxDataChangeListenerQueueSize,
+                DEFAULT_MAX_DATA_STORE_EXECUTOR_QUEUE_SIZE);
     }
 
     /**
@@ -54,10 +68,12 @@ public class InMemoryDOMDataStoreConfigProperties {
     }
 
     private InMemoryDOMDataStoreConfigProperties(int maxDataChangeExecutorPoolSize,
-            int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize) {
+            int maxDataChangeExecutorQueueSize, int maxDataChangeListenerQueueSize,
+            int maxDataStoreExecutorQueueSize) {
         this.maxDataChangeExecutorQueueSize = maxDataChangeExecutorQueueSize;
         this.maxDataChangeExecutorPoolSize = maxDataChangeExecutorPoolSize;
         this.maxDataChangeListenerQueueSize = maxDataChangeListenerQueueSize;
+        this.maxDataStoreExecutorQueueSize = maxDataStoreExecutorQueueSize;
     }
 
     /**
@@ -80,4 +96,11 @@ public class InMemoryDOMDataStoreConfigProperties {
     public int getMaxDataChangeListenerQueueSize() {
         return maxDataChangeListenerQueueSize;
     }
+
+    /**
+     * Returns the maximum queue size for the data store executor.
+     */
+    public int getMaxDataStoreExecutorQueueSize() {
+        return maxDataStoreExecutorQueueSize;
+    }
 }
index a3512743ed1a34acac5a1923983e06995e0d0f24..052fb2b89ba563c7be55612d75b48625f31de840 100644 (file)
@@ -9,13 +9,11 @@
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 import javax.annotation.Nullable;
 
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
-import com.google.common.util.concurrent.MoreExecutors;
 
 /**
  * A factory for creating InMemoryDOMDataStore instances.
@@ -61,9 +59,12 @@ public final class InMemoryDOMDataStoreFactory {
         ExecutorService dataChangeListenerExecutor = SpecialExecutors.newBlockingBoundedFastThreadPool(
                 dclExecutorMaxPoolSize, dclExecutorMaxQueueSize, name + "-DCL" );
 
+        ExecutorService domStoreExecutor = SpecialExecutors.newBoundedSingleThreadExecutor(
+                actualProperties.getMaxDataStoreExecutorQueueSize(), "DOMStore-" + name );
+
         InMemoryDOMDataStore dataStore = new InMemoryDOMDataStore(name,
-                MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()),
-                dataChangeListenerExecutor, actualProperties.getMaxDataChangeListenerQueueSize());
+                domStoreExecutor, dataChangeListenerExecutor,
+                actualProperties.getMaxDataChangeListenerQueueSize());
 
         if(schemaService != null) {
             schemaService.registerSchemaContextListener(dataStore);
index a4e8c86aa83f1b10f084f86f81a10feb08178d58..5fe9866b12ed0ec6e2a669de4cc7bd3b9957b641 100644 (file)
@@ -12,14 +12,10 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map.Entry;
-import java.util.concurrent.Callable;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
@@ -40,35 +36,23 @@ import org.slf4j.LoggerFactory;
  * Computes data change events for all affected registered listeners in data
  * tree.
  */
-final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
+final class ResolveDataChangeEventsTask {
     private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
 
-    @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
     private final DataTreeCandidate candidate;
     private final ListenerTree listenerRoot;
 
     private Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> collectedEvents;
 
-    @SuppressWarnings("rawtypes")
-    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree,
-            final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr) {
+    public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
         this.candidate = Preconditions.checkNotNull(candidate);
         this.listenerRoot = Preconditions.checkNotNull(listenerTree);
-        this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
     }
 
     /**
-     * Resolves and creates Notification Tasks
-     *
-     * Implementation of done as Map-Reduce with two steps: 1. resolving events
-     * and their mapping to listeners 2. merging events affecting same listener
-     *
-     * @return An {@link Iterable} of Notification Tasks which needs to be executed in
-     *         order to delivery data change events.
+     * Resolves and submits notification tasks to the specified manager.
      */
-    @Override
-    public synchronized Iterable<ChangeListenerNotifyTask> call() {
+    public synchronized void resolve(final NotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> manager) {
         try (final Walker w = listenerRoot.getWalker()) {
             // Defensive: reset internal state
             collectedEvents = ArrayListMultimap.create();
@@ -81,7 +65,6 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
              * Convert to tasks, but be mindful of multiple values -- those indicate multiple
              * wildcard matches, which need to be merged.
              */
-            final Collection<ChangeListenerNotifyTask> ret = new ArrayList<>();
             for (Entry<DataChangeListenerRegistration<?>, Collection<DOMImmutableDataChangeEvent>> e : collectedEvents.asMap().entrySet()) {
                 final Collection<DOMImmutableDataChangeEvent> col = e.getValue();
                 final DOMImmutableDataChangeEvent event;
@@ -98,12 +81,8 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
                     event = col.iterator().next();
                 }
 
-                ret.add(new ChangeListenerNotifyTask(e.getKey(), event, notificationMgr));
+                manager.submitNotification(e.getKey(), event);
             }
-
-            // FIXME: so now we have tasks to submit tasks... Inception-style!
-            LOG.debug("Created tasks {}", ret);
-            return ret;
         }
     }
 
@@ -333,10 +312,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         return scope != null;
     }
 
-    @SuppressWarnings("rawtypes")
-    public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate,
-            final ListenerTree listenerTree,
-            final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
-        return new ResolveDataChangeEventsTask(candidate, listenerTree, notificationMgr);
+    public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
+        return new ResolveDataChangeEventsTask(candidate, listenerTree);
     }
 }
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/jmx/InMemoryDataStoreStats.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/jmx/InMemoryDataStoreStats.java
new file mode 100644 (file)
index 0000000..b3608ec
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.sal.dom.store.impl.jmx;
+
+import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.md.sal.common.util.jmx.QueuedNotificationManagerMXBeanImpl;
+import org.opendaylight.controller.md.sal.common.util.jmx.ThreadExecutorStatsMXBeanImpl;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+
+/**
+ * Wrapper class for data store MXbeans.
+ *
+ * @author Thomas Pantelis
+ */
+public class InMemoryDataStoreStats implements AutoCloseable {
+
+    private final ThreadExecutorStatsMXBeanImpl notificationExecutorStatsBean;
+    private final ThreadExecutorStatsMXBeanImpl dataStoreExecutorStatsBean;
+    private final QueuedNotificationManagerMXBeanImpl notificationManagerStatsBean;
+
+    public InMemoryDataStoreStats(String mBeanType, QueuedNotificationManager<?, ?> manager,
+            ExecutorService dataStoreExecutor) {
+
+        this.notificationManagerStatsBean = new QueuedNotificationManagerMXBeanImpl(manager,
+                "notification-manager", mBeanType, null);
+        notificationManagerStatsBean.registerMBean();
+
+        this.notificationExecutorStatsBean = new ThreadExecutorStatsMXBeanImpl(manager.getExecutor(),
+                "notification-executor", mBeanType, null);
+        this.notificationExecutorStatsBean.registerMBean();
+
+        this.dataStoreExecutorStatsBean = new ThreadExecutorStatsMXBeanImpl(dataStoreExecutor,
+                "data-store-executor", mBeanType, null);
+        this.dataStoreExecutorStatsBean.registerMBean();
+    }
+
+    @Override
+    public void close() throws Exception {
+        if(notificationExecutorStatsBean != null) {
+            notificationExecutorStatsBean.unregisterMBean();
+        }
+
+        if(dataStoreExecutorStatsBean != null) {
+            dataStoreExecutorStatsBean.unregisterMBean();
+        }
+
+        if(notificationManagerStatsBean != null) {
+            notificationManagerStatsBean.unregisterMBean();
+        }
+    }
+}
index 17c86716d8c65183cf89130bbf9e8aa6c4f561e1..7d19a64446b519ea7795e86d81c6c431599ef7d9 100644 (file)
@@ -52,6 +52,12 @@ module opendaylight-inmemory-datastore-provider {
                 type uint16;
                 description "The maximum queue size for the data change listeners.";
             }
+
+            leaf max-data-store-executor-queue-size {
+                default 5000;
+                type uint16;
+                description "The maximum queue size for the data store executor.";
+            }
     }
 
     // Augments the 'configuration' choice node under modules/module.
index 23b039c2542540fe39d7af70b8ea0b0129e11aa3..e0b774f53c9008e3d8bd25772128e770b247419a 100644 (file)
@@ -156,7 +156,13 @@ public final class NetconfStateSchemas {
 
             QName childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_FORMAT.withoutRevision();
 
-            final String formatAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+            String formatAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+            //This is HotFix for situations where format statement in netconf-monitoring might be passed with prefix.
+            if (formatAsString.contains(":")) {
+                String[] prefixedString = formatAsString.split(":");
+                //FIXME: might be good idea to check prefix against model namespace
+                formatAsString = prefixedString[1];
+            }
             if(formatAsString.equals(Yang.QNAME.getLocalName()) == false) {
                 logger.debug("{}: Ignoring schema due to unsupported format: {}", id, formatAsString);
                 return Optional.absent();
index 6e92a2203792f6c262dd7aec4101a07d843b4e48..8d454c4bd6e43ef54aa8c8a24f659e6be1244f68 100644 (file)
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-data-api</artifactId>
-
     </dependency>
       <dependency>
           <groupId>org.opendaylight.yangtools</groupId>
           <artifactId>yang-model-api</artifactId>
-
       </dependency>
-
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-data-impl</artifactId>
-
     </dependency>
-
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-common</artifactId>
-
     </dependency>
-
-
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
     </dependency>
-
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
-
     <dependency>
       <groupId>org.scala-lang</groupId>
       <artifactId>scala-library</artifactId>
     <dependency>
       <groupId>com.codahale.metrics</groupId>
       <artifactId>metrics-core</artifactId>
-      <version>3.0.1</version>
     </dependency>
+
+      <dependency>
+          <groupId>com.codahale.metrics</groupId>
+          <artifactId>metrics-graphite</artifactId>
+      </dependency>
     <!-- Test Dependencies -->
     <dependency>
       <groupId>junit</groupId>
             <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
             <Export-package></Export-package>
             <Private-Package></Private-Package>
-            <Import-Package>!org.iq80.*;!*snappy;!org.jboss.*;!com.jcraft.*;!org.fusesource.*;*</Import-Package>
+            <Import-Package>!org.iq80.*;!*snappy;!org.jboss.*;!com.jcraft.*;!org.fusesource.*;!*jetty*;!sun.security.*;*</Import-Package>
+            <!--
             <Embed-Dependency>
                 sal-clustering-commons;
                 sal-akka-raft;
                 *uncommons*;
             </Embed-Dependency>
             <Embed-Transitive>true</Embed-Transitive>
+          -->
           </instructions>
         </configuration>
       </plugin>
index f1ca3ccd505e1b1732ad906f75f3662368fdc4a2..6a442c57cc5dfac799760c74d11dedff9668c833 100644 (file)
@@ -10,12 +10,16 @@ package org.opendaylight.controller.remote.rpc;
 
 import akka.actor.ActorSystem;
 import akka.osgi.BundleDelegatingClassLoader;
-import com.typesafe.config.ConfigFactory;
+import org.opendaylight.controller.remote.rpc.utils.AkkaConfigurationReader;
 import org.osgi.framework.BundleContext;
 
 
 public class ActorSystemFactory {
- private static volatile ActorSystem actorSystem = null;
+
+    public static final String ACTOR_SYSTEM_NAME = "opendaylight-cluster-rpc";
+    public static final String CONFIGURATION_NAME = "odl-cluster-rpc";
+
+    private static volatile ActorSystem actorSystem = null;
 
   public static final ActorSystem getInstance(){
      return actorSystem;
@@ -26,7 +30,7 @@ public class ActorSystemFactory {
    *
    * @param bundleContext
    */
-  public static final void createInstance(final BundleContext bundleContext) {
+  public static final void createInstance(final BundleContext bundleContext, AkkaConfigurationReader akkaConfigurationReader) {
     if(actorSystem == null) {
       // Create an OSGi bundle classloader for actor system
       BundleDelegatingClassLoader classLoader = new BundleDelegatingClassLoader(bundleContext.getBundle(),
@@ -34,8 +38,8 @@ public class ActorSystemFactory {
       synchronized (ActorSystemFactory.class) {
         // Double check
         if (actorSystem == null) {
-          ActorSystem system = ActorSystem.create("opendaylight-cluster-rpc",
-              ConfigFactory.load().getConfig("odl-cluster-rpc"), classLoader);
+          ActorSystem system = ActorSystem.create(ACTOR_SYSTEM_NAME,
+              akkaConfigurationReader.read().getConfig(CONFIGURATION_NAME), classLoader);
           actorSystem = system;
         }
       }
@@ -43,4 +47,5 @@ public class ActorSystemFactory {
       throw new IllegalStateException("Actor system should be created only once. Use getInstance method to access existing actor system");
     }
   }
+
 }
index 4496bd3263f9f80c6d1594e2e51de474ecb22a46..7d7dbf0f3a58bc404882ad78186340d8eef2aba9 100644 (file)
@@ -1,9 +1,13 @@
 package org.opendaylight.controller.remote.rpc;
 
+import static akka.pattern.Patterns.ask;
 import akka.actor.ActorRef;
-import com.google.common.util.concurrent.Futures;
+import akka.dispatch.OnComplete;
+import akka.util.Timeout;
+
 import com.google.common.util.concurrent.ListenableFuture;
-import org.opendaylight.controller.remote.rpc.messages.ErrorResponse;
+import com.google.common.util.concurrent.SettableFuture;
+
 import org.opendaylight.controller.remote.rpc.messages.InvokeRpc;
 import org.opendaylight.controller.remote.rpc.messages.RpcResponse;
 import org.opendaylight.controller.remote.rpc.utils.ActorUtil;
@@ -13,73 +17,82 @@ import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
 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;
 
+import scala.concurrent.ExecutionContext;
+
 import java.util.Collections;
 import java.util.Set;
 
-public class RemoteRpcImplementation implements RpcImplementation,
-    RoutedRpcDefaultImplementation {
-  private static final Logger LOG = LoggerFactory.getLogger(RemoteRpcImplementation.class);
-  private ActorRef rpcBroker;
-  private SchemaContext schemaContext;
-
-  public RemoteRpcImplementation(ActorRef rpcBroker, SchemaContext schemaContext) {
-    this.rpcBroker = rpcBroker;
-    this.schemaContext = schemaContext;
-  }
-
-  @Override
-  public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, YangInstanceIdentifier identifier, CompositeNode input) {
-    InvokeRpc rpcMsg = new InvokeRpc(rpc, identifier, input);
-
-    return executeMsg(rpcMsg);
-  }
-
-  @Override
-  public Set<QName> getSupportedRpcs() {
-    // TODO : check if we need to get this from routing registry
-    return Collections.emptySet();
-  }
-
-  @Override
-  public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
-    InvokeRpc rpcMsg = new InvokeRpc(rpc, null, input);
-    return executeMsg(rpcMsg);
-  }
-
-  private ListenableFuture<RpcResult<CompositeNode>> executeMsg(Object rpcMsg) {
-    ListenableFuture<RpcResult<CompositeNode>> listenableFuture = null;
-
-    try {
-      Object response = ActorUtil.executeOperation(rpcBroker, rpcMsg, ActorUtil.ASK_DURATION, ActorUtil.AWAIT_DURATION);
-      if(response instanceof RpcResponse) {
-
-        RpcResponse rpcResponse = (RpcResponse) response;
-        CompositeNode result = XmlUtils.xmlToCompositeNode(rpcResponse.getResultCompositeNode());
-        listenableFuture = Futures.immediateFuture(RpcResultBuilder.success(result).build());
-
-      } else if(response instanceof ErrorResponse) {
-
-        ErrorResponse errorResponse = (ErrorResponse) response;
-        Exception e = errorResponse.getException();
-        final RpcResultBuilder<CompositeNode> failed = RpcResultBuilder.failed();
-        failed.withError(null, null, e.getMessage(), null, null, e.getCause());
-        listenableFuture = Futures.immediateFuture(failed.build());
-
-      }
-    } catch (Exception e) {
-      LOG.error("Error occurred while invoking RPC actor {}", e);
-
-      final RpcResultBuilder<CompositeNode> failed = RpcResultBuilder.failed();
-      failed.withError(null, null, e.getMessage(), null, null, e.getCause());
-      listenableFuture = Futures.immediateFuture(failed.build());
+public class RemoteRpcImplementation implements RpcImplementation, RoutedRpcDefaultImplementation {
+    private static final Logger LOG = LoggerFactory.getLogger(RemoteRpcImplementation.class);
+    private final ActorRef rpcBroker;
+    private final SchemaContext schemaContext;
+
+    public RemoteRpcImplementation(ActorRef rpcBroker, SchemaContext schemaContext) {
+        this.rpcBroker = rpcBroker;
+        this.schemaContext = schemaContext;
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc,
+            YangInstanceIdentifier identifier, CompositeNode input) {
+        InvokeRpc rpcMsg = new InvokeRpc(rpc, identifier, input);
+
+        return executeMsg(rpcMsg);
+    }
+
+    @Override
+    public Set<QName> getSupportedRpcs() {
+        // TODO : check if we need to get this from routing registry
+        return Collections.emptySet();
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
+        InvokeRpc rpcMsg = new InvokeRpc(rpc, null, input);
+        return executeMsg(rpcMsg);
     }
 
-    return listenableFuture;
-  }
+    private ListenableFuture<RpcResult<CompositeNode>> executeMsg(InvokeRpc rpcMsg) {
+
+        final SettableFuture<RpcResult<CompositeNode>> listenableFuture = SettableFuture.create();
+
+        scala.concurrent.Future<Object> future = ask(rpcBroker, rpcMsg,
+                new Timeout(ActorUtil.ASK_DURATION));
+
+        OnComplete<Object> onComplete = new OnComplete<Object>() {
+            @Override
+            public void onComplete(Throwable failure, Object reply) throws Throwable {
+                if(failure != null) {
+                    LOG.error("InvokeRpc failed", failure);
+
+                    RpcResult<CompositeNode> rpcResult;
+                    if(failure instanceof RpcErrorsException) {
+                        rpcResult = RpcResultBuilder.<CompositeNode>failed().withRpcErrors(
+                                ((RpcErrorsException)failure).getRpcErrors()).build();
+                    } else {
+                        rpcResult = RpcResultBuilder.<CompositeNode>failed().withError(
+                                ErrorType.RPC, failure.getMessage(), failure).build();
+                    }
+
+                    listenableFuture.set(rpcResult);
+                    return;
+                }
+
+                RpcResponse rpcReply = (RpcResponse)reply;
+                CompositeNode result = XmlUtils.xmlToCompositeNode(rpcReply.getResultCompositeNode());
+                listenableFuture.set(RpcResultBuilder.success(result).build());
+            }
+        };
+
+        future.onComplete(onComplete, ExecutionContext.Implicits$.MODULE$.global());
+
+        return listenableFuture;
+    }
 }
index fc75f7747a0d25361c96f96e77aac30538bb05a5..0e6b795c058877069640a848fe1144575db37443 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.controller.remote.rpc;
 
 
+import org.opendaylight.controller.remote.rpc.utils.DefaultAkkaConfigurationReader;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.osgi.framework.BundleContext;
@@ -16,7 +17,7 @@ import org.osgi.framework.BundleContext;
 public class RemoteRpcProviderFactory {
     public static RemoteRpcProvider createInstance(final Broker broker, final BundleContext bundleContext){
 
-      ActorSystemFactory.createInstance(bundleContext);
+      ActorSystemFactory.createInstance(bundleContext, new DefaultAkkaConfigurationReader());
       RemoteRpcProvider rpcProvider =
           new RemoteRpcProvider(ActorSystemFactory.getInstance(), (RpcProvisionRegistry) broker);
       broker.registerProvider(rpcProvider);
index 4ec96c29cd2510175defa6327a235ffecb519b28..2aca655d2628eb9d89295d09419d0cd44f7491d7 100644 (file)
@@ -8,11 +8,14 @@
 
 package org.opendaylight.controller.remote.rpc;
 
+import static akka.pattern.Patterns.ask;
 import akka.actor.ActorRef;
 import akka.actor.Props;
+import akka.dispatch.OnComplete;
 import akka.japi.Creator;
 import akka.japi.Pair;
-import org.opendaylight.controller.remote.rpc.messages.ErrorResponse;
+import akka.util.Timeout;
+
 import org.opendaylight.controller.remote.rpc.messages.ExecuteRpc;
 import org.opendaylight.controller.remote.rpc.messages.InvokeRpc;
 import org.opendaylight.controller.remote.rpc.messages.RpcResponse;
@@ -23,12 +26,23 @@ import org.opendaylight.controller.remote.rpc.utils.RoutingLogic;
 import org.opendaylight.controller.xml.codec.XmlUtils;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
 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.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.Future;
 
@@ -38,81 +52,159 @@ import java.util.concurrent.Future;
 
 public class RpcBroker extends AbstractUntypedActor {
 
-  private static final Logger LOG = LoggerFactory.getLogger(RpcBroker.class);
-  private final Broker.ProviderSession brokerSession;
-  private final ActorRef rpcRegistry;
-  private SchemaContext schemaContext;
-
-  private RpcBroker(Broker.ProviderSession brokerSession, ActorRef rpcRegistry, SchemaContext schemaContext){
-    this.brokerSession = brokerSession;
-    this.rpcRegistry = rpcRegistry;
-    this.schemaContext = schemaContext;
-  }
-
-  public static Props props(final Broker.ProviderSession brokerSession, final ActorRef rpcRegistry, final SchemaContext schemaContext){
-    return Props.create(new Creator<RpcBroker>(){
-
-      @Override
-      public RpcBroker create() throws Exception {
-        return new RpcBroker(brokerSession, rpcRegistry, schemaContext);
-      }
-    });
-  }
-  @Override
-  protected void handleReceive(Object message) throws Exception {
-   if(message instanceof InvokeRpc) {
-      invokeRemoteRpc((InvokeRpc) message);
-    } else if(message instanceof ExecuteRpc) {
-      executeRpc((ExecuteRpc) message);
+    private static final Logger LOG = LoggerFactory.getLogger(RpcBroker.class);
+    private final Broker.ProviderSession brokerSession;
+    private final ActorRef rpcRegistry;
+    private final SchemaContext schemaContext;
+
+    private RpcBroker(Broker.ProviderSession brokerSession, ActorRef rpcRegistry,
+            SchemaContext schemaContext) {
+        this.brokerSession = brokerSession;
+        this.rpcRegistry = rpcRegistry;
+        this.schemaContext = schemaContext;
     }
-  }
-
-  private void invokeRemoteRpc(InvokeRpc msg) {
-    // Look up the remote actor to execute rpc
-    LOG.debug("Looking up the remote actor for route {}", msg);
-    try {
-      // Find router
-      RpcRouter.RouteIdentifier<?,?,?> routeId = new RouteIdentifierImpl(null, msg.getRpc(), msg.getIdentifier());
-      RpcRegistry.Messages.FindRouters rpcMsg = new RpcRegistry.Messages.FindRouters(routeId);
-      RpcRegistry.Messages.FindRoutersReply rpcReply =
-          (RpcRegistry.Messages.FindRoutersReply) ActorUtil.executeOperation(rpcRegistry, rpcMsg, ActorUtil.LOCAL_ASK_DURATION, ActorUtil.LOCAL_AWAIT_DURATION);
-
-      List<Pair<ActorRef, Long>> actorRefList = rpcReply.getRouterWithUpdateTime();
-
-      if(actorRefList == null || actorRefList.isEmpty()) {
-        LOG.debug("No remote actor found for rpc {{}}.", msg.getRpc());
-
-        getSender().tell(new ErrorResponse(
-            new IllegalStateException("No remote actor found for rpc execution of : " + msg.getRpc())), self());
-      } else {
-        RoutingLogic logic = new LatestEntryRoutingLogic(actorRefList);
 
-        ExecuteRpc executeMsg = new ExecuteRpc(XmlUtils.inputCompositeNodeToXml(msg.getInput(), schemaContext), msg.getRpc());
-        Object operationRes = ActorUtil.executeOperation(logic.select(),
-            executeMsg, ActorUtil.REMOTE_ASK_DURATION, ActorUtil.REMOTE_AWAIT_DURATION);
+    public static Props props(Broker.ProviderSession brokerSession, ActorRef rpcRegistry,
+            SchemaContext schemaContext) {
+        return Props.create(new RpcBrokerCreator(brokerSession, rpcRegistry, schemaContext));
+    }
 
-        getSender().tell(operationRes, self());
-      }
-    } catch (Exception e) {
-        LOG.error("invokeRemoteRpc: {}", e);
-        getSender().tell(new ErrorResponse(e), self());
+    @Override
+    protected void handleReceive(Object message) throws Exception {
+        if(message instanceof InvokeRpc) {
+            invokeRemoteRpc((InvokeRpc) message);
+        } else if(message instanceof ExecuteRpc) {
+            executeRpc((ExecuteRpc) message);
+        }
     }
-  }
 
+    private void invokeRemoteRpc(final InvokeRpc msg) {
+        LOG.debug("Looking up the remote actor for rpc {}", msg.getRpc());
+
+        RpcRouter.RouteIdentifier<?,?,?> routeId = new RouteIdentifierImpl(
+                null, msg.getRpc(), msg.getIdentifier());
+        RpcRegistry.Messages.FindRouters findMsg = new RpcRegistry.Messages.FindRouters(routeId);
+
+        scala.concurrent.Future<Object> future = ask(rpcRegistry, findMsg,
+                new Timeout(ActorUtil.LOCAL_ASK_DURATION));
 
+        final ActorRef sender = getSender();
+        final ActorRef self = self();
 
-  private void executeRpc(ExecuteRpc msg) {
-    LOG.debug("Executing rpc for rpc {}", msg.getRpc());
-    try {
-      Future<RpcResult<CompositeNode>> rpc = brokerSession.rpc(msg.getRpc(),
-          XmlUtils.inputXmlToCompositeNode(msg.getRpc(), msg.getInputCompositeNode(), schemaContext));
-      RpcResult<CompositeNode> rpcResult = rpc != null ? rpc.get():null;
-      CompositeNode result = rpcResult != null ? rpcResult.getResult() : null;
-      getSender().tell(new RpcResponse(XmlUtils.outputCompositeNodeToXml(result, schemaContext)), self());
-    } catch (Exception e) {
-      LOG.error("executeRpc: {}", e);
-      getSender().tell(new ErrorResponse(e), self());
+        OnComplete<Object> onComplete = new OnComplete<Object>() {
+            @Override
+            public void onComplete(Throwable failure, Object reply) throws Throwable {
+                if(failure != null) {
+                    LOG.error("FindRouters failed", failure);
+                    sender.tell(new akka.actor.Status.Failure(failure), self);
+                    return;
+                }
+
+                RpcRegistry.Messages.FindRoutersReply findReply =
+                                                (RpcRegistry.Messages.FindRoutersReply)reply;
+
+                List<Pair<ActorRef, Long>> actorRefList = findReply.getRouterWithUpdateTime();
+
+                if(actorRefList == null || actorRefList.isEmpty()) {
+                    String message = String.format(
+                            "No remote implementation found for rpc %s",  msg.getRpc());
+                    sender.tell(new akka.actor.Status.Failure(new RpcErrorsException(
+                            message, Arrays.asList(RpcResultBuilder.newError(ErrorType.RPC,
+                                    "operation-not-supported", message)))), self);
+                    return;
+                }
+
+                finishInvokeRpc(actorRefList, msg, sender, self);
+            }
+        };
+
+        future.onComplete(onComplete, getContext().dispatcher());
     }
-  }
 
+    protected void finishInvokeRpc(final List<Pair<ActorRef, Long>> actorRefList,
+            final InvokeRpc msg, final ActorRef sender, final ActorRef self) {
+
+        RoutingLogic logic = new LatestEntryRoutingLogic(actorRefList);
+
+        ExecuteRpc executeMsg = new ExecuteRpc(XmlUtils.inputCompositeNodeToXml(msg.getInput(),
+                schemaContext), msg.getRpc());
+
+        scala.concurrent.Future<Object> future = ask(logic.select(), executeMsg,
+                new Timeout(ActorUtil.REMOTE_ASK_DURATION));
+
+        OnComplete<Object> onComplete = new OnComplete<Object>() {
+            @Override
+            public void onComplete(Throwable failure, Object reply) throws Throwable {
+                if(failure != null) {
+                    LOG.error("ExecuteRpc failed", failure);
+                    sender.tell(new akka.actor.Status.Failure(failure), self);
+                    return;
+                }
+
+                sender.tell(reply, self);
+            }
+        };
+
+        future.onComplete(onComplete, getContext().dispatcher());
+    }
+
+    private void executeRpc(final ExecuteRpc msg) {
+        LOG.debug("Executing rpc {}", msg.getRpc());
+
+        Future<RpcResult<CompositeNode>> future = brokerSession.rpc(msg.getRpc(),
+                XmlUtils.inputXmlToCompositeNode(msg.getRpc(), msg.getInputCompositeNode(),
+                        schemaContext));
+
+        ListenableFuture<RpcResult<CompositeNode>> listenableFuture =
+                JdkFutureAdapters.listenInPoolThread(future);
+
+        final ActorRef sender = getSender();
+        final ActorRef self = self();
+
+        Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<CompositeNode>>() {
+            @Override
+            public void onSuccess(RpcResult<CompositeNode> result) {
+                if(result.isSuccessful()) {
+                    sender.tell(new RpcResponse(XmlUtils.outputCompositeNodeToXml(result.getResult(),
+                            schemaContext)), self);
+                } else {
+                    String message = String.format("Execution of RPC %s failed",  msg.getRpc());
+                    Collection<RpcError> errors = result.getErrors();
+                    if(errors == null || errors.size() == 0) {
+                        errors = Arrays.asList(RpcResultBuilder.newError(ErrorType.RPC,
+                                null, message));
+                    }
+
+                    sender.tell(new akka.actor.Status.Failure(new RpcErrorsException(
+                            message, errors)), self);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.error("executeRpc for {} failed: {}", msg.getRpc(), t);
+                sender.tell(new akka.actor.Status.Failure(t), self);
+            }
+        });
+    }
+
+    private static class RpcBrokerCreator implements Creator<RpcBroker> {
+        private static final long serialVersionUID = 1L;
+
+        final Broker.ProviderSession brokerSession;
+        final ActorRef rpcRegistry;
+        final SchemaContext schemaContext;
+
+        RpcBrokerCreator(ProviderSession brokerSession, ActorRef rpcRegistry,
+                SchemaContext schemaContext) {
+            this.brokerSession = brokerSession;
+            this.rpcRegistry = rpcRegistry;
+            this.schemaContext = schemaContext;
+        }
+
+        @Override
+        public RpcBroker create() throws Exception {
+            return new RpcBroker(brokerSession, rpcRegistry, schemaContext);
+        }
+    }
 }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcErrorsException.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcErrorsException.java
new file mode 100644 (file)
index 0000000..7e4d8a0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.remote.rpc;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * An Exception for transferring RpcErrors.
+ *
+ * @author Thomas Pantelis
+ */
+public class RpcErrorsException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    private static class RpcErrorData implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        final ErrorSeverity severity;
+        final ErrorType errorType;
+        final String tag;
+        final String applicationTag;
+        final String message;
+        final String info;
+        final Throwable cause;
+
+        RpcErrorData(ErrorSeverity severity, ErrorType errorType, String tag,
+                String applicationTag, String message, String info, Throwable cause) {
+            this.severity = severity;
+            this.errorType = errorType;
+            this.tag = tag;
+            this.applicationTag = applicationTag;
+            this.message = message;
+            this.info = info;
+            this.cause = cause;
+        }
+    }
+
+    private final List<RpcErrorData> rpcErrorDataList = new ArrayList<>();
+
+    public RpcErrorsException(String message, Iterable<RpcError> rpcErrors) {
+        super(message);
+
+        for(RpcError rpcError: rpcErrors) {
+            rpcErrorDataList.add(new RpcErrorData(rpcError.getSeverity(), rpcError.getErrorType(),
+                    rpcError.getTag(), rpcError.getApplicationTag(), rpcError.getMessage(),
+                    rpcError.getInfo(), rpcError.getCause()));
+        }
+    }
+
+    public Collection<RpcError> getRpcErrors() {
+        Collection<RpcError> rpcErrors = new ArrayList<>();
+        for(RpcErrorData ed: rpcErrorDataList) {
+            RpcError rpcError = ed.severity == ErrorSeverity.ERROR ?
+                    RpcResultBuilder.newError(ed.errorType, ed.tag, ed.message, ed.applicationTag,
+                            ed.info, ed.cause) :
+                    RpcResultBuilder.newWarning(ed.errorType, ed.tag, ed.message, ed.applicationTag,
+                            ed.info, ed.cause);
+            rpcErrors.add(rpcError);
+        }
+
+        return rpcErrors;
+    }
+}
index 96f24724286192131c08177943a572c45dba5a96..d4da226b9dc4278cd508e83082283a3163c6615c 100644 (file)
@@ -15,8 +15,11 @@ import akka.actor.Props;
 import akka.actor.SupervisorStrategy;
 import akka.japi.Creator;
 import akka.japi.Function;
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
 import org.opendaylight.controller.remote.rpc.messages.UpdateSchemaContext;
 import org.opendaylight.controller.remote.rpc.registry.RpcRegistry;
+import org.opendaylight.controller.remote.rpc.utils.ActorUtil;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -69,10 +72,16 @@ public class RpcManager extends AbstractUntypedActor {
   private void createRpcActors() {
     LOG.debug("Create rpc registry and broker actors");
 
+      Config conf = ConfigFactory.load();
 
-    rpcRegistry = getContext().actorOf(Props.create(RpcRegistry.class), ActorConstants.RPC_REGISTRY);
+    rpcRegistry =
+            getContext().actorOf(Props.create(RpcRegistry.class).
+                withMailbox(ActorUtil.MAILBOX), ActorConstants.RPC_REGISTRY);
+
+    rpcBroker =
+            getContext().actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext).
+                withMailbox(ActorUtil.MAILBOX),ActorConstants.RPC_BROKER);
 
-    rpcBroker = getContext().actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext), ActorConstants.RPC_BROKER);
     RpcRegistry.Messages.SetLocalRouter localRouter = new RpcRegistry.Messages.SetLocalRouter(rpcBroker);
     rpcRegistry.tell(localRouter, self());
   }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/ErrorResponse.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/messages/ErrorResponse.java
deleted file mode 100644 (file)
index 2c26243..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.remote.rpc.messages;
-
-import com.google.common.base.Preconditions;
-
-import java.io.Serializable;
-
-public class ErrorResponse implements Serializable {
-
-  private final Exception exception;
-
-  public ErrorResponse(final Exception e) {
-    Preconditions.checkNotNull(e, "Exception should be present for error message");
-    this.exception = e;
-  }
-
-  public Exception getException() {
-    return exception;
-  }
-}
index 76f59304576b731f1a15df9c277628ad9ff611d6..5109d316446b13158e3739824e653e0259929135 100644 (file)
@@ -20,6 +20,7 @@ import akka.pattern.Patterns;
 import com.google.common.base.Preconditions;
 import org.opendaylight.controller.remote.rpc.registry.gossip.Bucket;
 import org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore;
+import org.opendaylight.controller.remote.rpc.utils.ActorUtil;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import scala.concurrent.Future;
 
@@ -107,7 +108,7 @@ public class RpcRegistry extends UntypedActor {
 
         Preconditions.checkState(localRouter != null, "Router must be set first");
 
-        Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), 1000);
+        Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), ActorUtil.ASK_DURATION.toMillis());
         futureReply.map(getMapperToAddRoutes(msg.getRouteIdentifiers()), getContext().dispatcher());
     }
 
@@ -116,7 +117,7 @@ public class RpcRegistry extends UntypedActor {
      */
     private void receiveRemoveRoutes(RemoveRoutes msg) {
 
-        Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), 1000);
+        Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), ActorUtil.ASK_DURATION.toMillis());
         futureReply.map(getMapperToRemoveRoutes(msg.getRouteIdentifiers()), getContext().dispatcher());
 
     }
@@ -129,7 +130,7 @@ public class RpcRegistry extends UntypedActor {
     private void receiveGetRouter(FindRouters msg) {
         final ActorRef sender = getSender();
 
-        Future<Object> futureReply = Patterns.ask(bucketStore, new GetAllBuckets(), 1000);
+        Future<Object> futureReply = Patterns.ask(bucketStore, new GetAllBuckets(), ActorUtil.ASK_DURATION.toMillis());
         futureReply.map(getMapperToGetRouter(msg.getRouteIdentifier(), sender), getContext().dispatcher());
     }
 
index 3b078aa062fdf1fc3feaca7fa10147de8c3503cc..ff51f4fcfa671ff4ae71be72c6403b741e3de8dd 100644 (file)
@@ -16,6 +16,7 @@ import akka.actor.UntypedActor;
 import akka.cluster.ClusterActorRefProvider;
 import akka.event.Logging;
 import akka.event.LoggingAdapter;
+import org.opendaylight.controller.remote.rpc.utils.ActorUtil;
 import org.opendaylight.controller.utils.ConditionalProbe;
 
 import java.util.HashMap;
@@ -76,7 +77,7 @@ public class BucketStore extends UntypedActor {
         selfAddress = provider.getDefaultAddress();
 
         if ( provider instanceof ClusterActorRefProvider)
-            getContext().actorOf(Props.create(Gossiper.class), "gossiper");
+            getContext().actorOf(Props.create(Gossiper.class).withMailbox(ActorUtil.MAILBOX), "gossiper");
     }
 
     @Override
index a8bc25c40ba14b2ecf8c45926f7871f189dbdafa..f6ce5e55f3ee63602fc92529e92d6e93d0ff9bb3 100644 (file)
@@ -21,6 +21,7 @@ import akka.dispatch.Mapper;
 import akka.event.Logging;
 import akka.event.LoggingAdapter;
 import akka.pattern.Patterns;
+import org.opendaylight.controller.remote.rpc.utils.ActorUtil;
 import scala.concurrent.Future;
 import scala.concurrent.duration.FiniteDuration;
 
@@ -105,7 +106,7 @@ public class Gossiper extends UntypedActor {
         if (autoStartGossipTicks) {
             gossipTask = getContext().system().scheduler().schedule(
                     new FiniteDuration(1, TimeUnit.SECONDS),        //initial delay
-                    new FiniteDuration(500, TimeUnit.MILLISECONDS), //interval
+                    ActorUtil.GOSSIP_TICK_INTERVAL,                 //interval
                     getSelf(),                                       //target
                     new Messages.GossiperMessages.GossipTick(),      //message
                     getContext().dispatcher(),                       //execution context
@@ -227,7 +228,9 @@ public class Gossiper extends UntypedActor {
             return;
 
         final ActorRef sender = getSender();
-        Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketVersions(), 1000);
+        Future<Object> futureReply =
+                Patterns.ask(getContext().parent(), new GetBucketVersions(), ActorUtil.ASK_DURATION.toMillis());
+
         futureReply.map(getMapperToProcessRemoteStatus(sender, status), getContext().dispatcher());
 
     }
@@ -267,7 +270,8 @@ public class Gossiper extends UntypedActor {
      */
     void sendGossipTo(final ActorRef remote, final Set<Address> addresses){
 
-        Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketsByMembers(addresses), 1000);
+        Future<Object> futureReply =
+                Patterns.ask(getContext().parent(), new GetBucketsByMembers(addresses), ActorUtil.ASK_DURATION.toMillis());
         futureReply.map(getMapperToSendGossip(remote), getContext().dispatcher());
     }
 
@@ -279,7 +283,10 @@ public class Gossiper extends UntypedActor {
     void getLocalStatusAndSendTo(Address remoteActorSystemAddress){
 
         //Get local status from bucket store and send to remote
-        Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketVersions(), 1000);
+        Future<Object> futureReply =
+                Patterns.ask(getContext().parent(), new GetBucketVersions(), ActorUtil.ASK_DURATION.toMillis());
+
+        //Find gossiper on remote system
         ActorSelection remoteRef = getContext().system().actorSelection(
                 remoteActorSystemAddress.toString() + getSelf().path().toStringWithoutAddress());
 
index b7b2216a08b0293fccc733836355ed8e4bd5767a..e2baffa1b13a02e294a8ff2f83361f41b0dd83e9 100644 (file)
@@ -8,40 +8,15 @@
  */
 package org.opendaylight.controller.remote.rpc.utils;
 
-import akka.actor.ActorRef;
-import akka.util.Timeout;
-import scala.concurrent.Await;
-import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
 import scala.concurrent.duration.FiniteDuration;
 
 import java.util.concurrent.TimeUnit;
 
-import static akka.pattern.Patterns.ask;
-
 public class ActorUtil {
-  public static final FiniteDuration LOCAL_ASK_DURATION = Duration.create(2, TimeUnit.SECONDS);
-  public static final FiniteDuration REMOTE_ASK_DURATION = Duration.create(15, TimeUnit.SECONDS);
-  public static final FiniteDuration ASK_DURATION = Duration.create(17, TimeUnit.SECONDS);
-  public static final FiniteDuration LOCAL_AWAIT_DURATION = Duration.create(2, TimeUnit.SECONDS);
-  public static final FiniteDuration REMOTE_AWAIT_DURATION = Duration.create(15, TimeUnit.SECONDS);
-  public static final FiniteDuration AWAIT_DURATION = Duration.create(17, TimeUnit.SECONDS);
-
-  /**
-   * Executes an operation on a local actor and wait for it's response
-   * @param actor
-   * @param message
-   * @param askDuration
-   * @param awaitDuration
-   * @return The response of the operation
-   */
-  public static Object executeOperation(ActorRef actor, Object message,
-                                        FiniteDuration askDuration, FiniteDuration awaitDuration) throws Exception{
-    Future<Object> future =
-        ask(actor, message, new Timeout(askDuration));
-
-      return Await.result(future, awaitDuration);
-  }
-
-
+    public static final FiniteDuration LOCAL_ASK_DURATION = Duration.create(2, TimeUnit.SECONDS);
+    public static final FiniteDuration REMOTE_ASK_DURATION = Duration.create(15, TimeUnit.SECONDS);
+    public static final FiniteDuration ASK_DURATION = Duration.create(17, TimeUnit.SECONDS);
+    public static final FiniteDuration GOSSIP_TICK_INTERVAL = Duration.create(500, TimeUnit.MILLISECONDS);
+    public static final String MAILBOX = "bounded-mailbox";
 }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/AkkaConfigurationReader.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/AkkaConfigurationReader.java
new file mode 100644 (file)
index 0000000..035ce9a
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.remote.rpc.utils;
+
+import com.typesafe.config.Config;
+
+public interface AkkaConfigurationReader {
+    Config read();
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/DefaultAkkaConfigurationReader.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/utils/DefaultAkkaConfigurationReader.java
new file mode 100644 (file)
index 0000000..a44d20c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.remote.rpc.utils;
+
+import com.google.common.base.Preconditions;
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+
+import java.io.File;
+
+public class DefaultAkkaConfigurationReader implements AkkaConfigurationReader {
+    public static final String AKKA_CONF_PATH = "./configuration/initial/akka.conf";
+
+    @Override public Config read() {
+        File defaultConfigFile = new File(AKKA_CONF_PATH);
+        Preconditions.checkState(defaultConfigFile.exists(), "akka.conf is missing");
+        return ConfigFactory.parseFile(defaultConfigFile);
+
+    }
+}
index 711ae1c48b75c794bad3cb93de12e397632bcbfd..266832a0ab0491dfd5d58d2c0414c2733ef0300b 100644 (file)
@@ -38,10 +38,15 @@ odl-cluster-data {
 }
 
 odl-cluster-rpc {
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 100ms
+  }
+
   akka {
     actor {
       provider = "akka.cluster.ClusterActorRefProvider"
-
     }
     remote {
       log-remote-lifecycle-events = off
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/AbstractRpcTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/AbstractRpcTest.java
new file mode 100644 (file)
index 0000000..8d88682
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.remote.rpc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.mockito.Mockito;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.testkit.JavaTestKit;
+
+import com.google.common.collect.ImmutableList;
+import com.typesafe.config.ConfigFactory;
+
+/**
+ * Base class for RPC tests.
+ *
+ * @author Thomas Pantelis
+ */
+public class AbstractRpcTest {
+    static final String TEST_REV = "2014-08-28";
+    static final String TEST_NS = "urn:test";
+    static final URI TEST_URI = URI.create(TEST_NS);
+    static final QName TEST_RPC = QName.create(TEST_NS, TEST_REV, "test-rpc");
+    static final QName TEST_RPC_INPUT = QName.create(TEST_NS, TEST_REV, "input");
+    static final QName TEST_RPC_INPUT_DATA = QName.create(TEST_NS, TEST_REV, "input-data");
+    static final QName TEST_RPC_OUTPUT = QName.create(TEST_NS, TEST_REV, "output");
+    static final QName TEST_RPC_OUTPUT_DATA = new QName(TEST_URI, "output-data");
+
+    static ActorSystem node1;
+    static ActorSystem node2;
+
+    protected ActorRef rpcBroker1;
+    protected JavaTestKit probeReg1;
+    protected ActorRef rpcBroker2;
+    protected JavaTestKit probeReg2;
+    protected Broker.ProviderSession brokerSession;
+    protected SchemaContext schemaContext;
+
+    @BeforeClass
+    public static void setup() throws InterruptedException {
+        node1 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberA"));
+        node2 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberB"));
+    }
+
+    @AfterClass
+    public static void teardown() {
+        JavaTestKit.shutdownActorSystem(node1);
+        JavaTestKit.shutdownActorSystem(node2);
+        node1 = null;
+        node2 = null;
+    }
+
+    @Before
+    public void setUp() {
+        schemaContext = new YangParserImpl().parseFiles(Arrays.asList(
+                new File(RpcBrokerTest.class.getResource("/test-rpc.yang").getPath())));
+
+        brokerSession = Mockito.mock(Broker.ProviderSession.class);
+        probeReg1 = new JavaTestKit(node1);
+        rpcBroker1 = node1.actorOf(RpcBroker.props(brokerSession, probeReg1.getRef(), schemaContext));
+        probeReg2 = new JavaTestKit(node2);
+        rpcBroker2 = node2.actorOf(RpcBroker.props(brokerSession, probeReg2.getRef(), schemaContext));
+
+    }
+
+    static void assertRpcErrorEquals(RpcError rpcError, ErrorSeverity severity,
+            ErrorType errorType, String tag, String message, String applicationTag, String info,
+            String causeMsg) {
+        assertEquals("getSeverity", severity, rpcError.getSeverity());
+        assertEquals("getErrorType", errorType, rpcError.getErrorType());
+        assertEquals("getTag", tag, rpcError.getTag());
+        assertTrue("getMessage contains " + message, rpcError.getMessage().contains(message));
+        assertEquals("getApplicationTag", applicationTag, rpcError.getApplicationTag());
+        assertEquals("getInfo", info, rpcError.getInfo());
+
+        if(causeMsg == null) {
+            assertNull("Unexpected cause " + rpcError.getCause(), rpcError.getCause());
+        } else {
+            assertEquals("Cause message", causeMsg, rpcError.getCause().getMessage());
+        }
+    }
+
+    static void assertCompositeNodeEquals(CompositeNode exp, CompositeNode actual) {
+        assertEquals("NodeType getNamespace", exp.getNodeType().getNamespace(),
+                actual.getNodeType().getNamespace());
+        assertEquals("NodeType getLocalName", exp.getNodeType().getLocalName(),
+                actual.getNodeType().getLocalName());
+        for(Node<?> child: exp.getValue()) {
+            List<Node<?>> c = actual.get(child.getNodeType());
+            assertNotNull("Missing expected child " + child.getNodeType(), c);
+            if(child instanceof CompositeNode) {
+                assertCompositeNodeEquals((CompositeNode) child, (CompositeNode)c.get(0));
+            } else {
+                assertEquals("Value for Node " + child.getNodeType(), child.getValue(),
+                        c.get(0).getValue());
+            }
+        }
+    }
+
+    static CompositeNode makeRPCInput(String data) {
+        CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder()
+                .setQName(TEST_RPC_INPUT).addLeaf(TEST_RPC_INPUT_DATA, data);
+        return ImmutableCompositeNode.create(
+                TEST_RPC, ImmutableList.<Node<?>>of(builder.toInstance()));
+    }
+
+    static CompositeNode makeRPCOutput(String data) {
+        CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder()
+                .setQName(TEST_RPC_OUTPUT).addLeaf(TEST_RPC_OUTPUT_DATA, data);
+        return ImmutableCompositeNode.create(
+                TEST_RPC, ImmutableList.<Node<?>>of(builder.toInstance()));
+    }
+
+    static void assertFailedRpcResult(RpcResult<CompositeNode> rpcResult, ErrorSeverity severity,
+            ErrorType errorType, String tag, String message, String applicationTag, String info,
+            String causeMsg) {
+
+        assertNotNull("RpcResult was null", rpcResult);
+        assertEquals("isSuccessful", false, rpcResult.isSuccessful());
+        Collection<RpcError> rpcErrors = rpcResult.getErrors();
+        assertEquals("RpcErrors count", 1, rpcErrors.size());
+        assertRpcErrorEquals(rpcErrors.iterator().next(), severity, errorType, tag, message,
+                applicationTag, info, causeMsg);
+    }
+
+    static void assertSuccessfulRpcResult(RpcResult<CompositeNode> rpcResult,
+            CompositeNode expOutput) {
+
+        assertNotNull("RpcResult was null", rpcResult);
+        assertEquals("isSuccessful", true, rpcResult.isSuccessful());
+        assertCompositeNodeEquals(expOutput, rpcResult.getResult());
+    }
+
+    static class TestException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        static final String MESSAGE = "mock error";
+
+        TestException() {
+            super(MESSAGE);
+        }
+    }
+}
index ed5fa6d16e330bbf8907aad6a0341b5d543c1952..cd1cd918693c15a2f8343ed46e8fba97b50c7a8a 100644 (file)
@@ -10,9 +10,11 @@ package org.opendaylight.controller.remote.rpc;
 
 
 import akka.actor.ActorSystem;
+import com.typesafe.config.ConfigFactory;
 import junit.framework.Assert;
 import org.junit.After;
 import org.junit.Test;
+import org.opendaylight.controller.remote.rpc.utils.AkkaConfigurationReader;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 
@@ -27,13 +29,17 @@ public class ActorSystemFactoryTest {
   public void testActorSystemCreation(){
     BundleContext context = mock(BundleContext.class);
     when(context.getBundle()).thenReturn(mock(Bundle.class));
-    ActorSystemFactory.createInstance(context);
+
+    AkkaConfigurationReader reader = mock(AkkaConfigurationReader.class);
+    when(reader.read()).thenReturn(ConfigFactory.load());
+
+    ActorSystemFactory.createInstance(context, reader);
     system = ActorSystemFactory.getInstance();
     Assert.assertNotNull(system);
     // Check illegal state exception
 
     try {
-      ActorSystemFactory.createInstance(context);
+      ActorSystemFactory.createInstance(context, reader);
       fail("Illegal State exception should be thrown, while creating actor system second time");
     } catch (IllegalStateException e) {
     }
@@ -45,5 +51,4 @@ public class ActorSystemFactoryTest {
       system.shutdown();
     }
   }
-
 }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementationTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RemoteRpcImplementationTest.java
new file mode 100644 (file)
index 0000000..6c3a57b
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.remote.rpc;
+
+import static org.junit.Assert.assertEquals;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.Test;
+import org.opendaylight.controller.remote.rpc.messages.InvokeRpc;
+import org.opendaylight.controller.remote.rpc.messages.RpcResponse;
+import org.opendaylight.controller.xml.codec.XmlUtils;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+import akka.testkit.JavaTestKit;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/***
+ * Unit tests for RemoteRpcImplementation.
+ *
+ * @author Thomas Pantelis
+ */
+public class RemoteRpcImplementationTest extends AbstractRpcTest {
+
+    @Test
+    public void testInvokeRpc() throws Exception {
+        final AtomicReference<AssertionError> assertError = new AtomicReference<>();
+        try {
+            RemoteRpcImplementation rpcImpl = new RemoteRpcImplementation(
+                    probeReg1.getRef(), schemaContext);
+
+            final CompositeNode input = makeRPCInput("foo");
+            final CompositeNode output = makeRPCOutput("bar");
+            final AtomicReference<InvokeRpc> invokeRpcMsg = setupInvokeRpcReply(assertError, output);
+
+            ListenableFuture<RpcResult<CompositeNode>> future = rpcImpl.invokeRpc(TEST_RPC, input);
+
+            RpcResult<CompositeNode> rpcResult = future.get(5, TimeUnit.SECONDS);
+
+            assertSuccessfulRpcResult(rpcResult, (CompositeNode)output.getValue().get(0));
+
+            assertEquals("getRpc", TEST_RPC, invokeRpcMsg.get().getRpc());
+            assertEquals("getInput", input, invokeRpcMsg.get().getInput());
+        } finally {
+            if(assertError.get() != null) {
+                throw assertError.get();
+            }
+        }
+    }
+
+    @Test
+    public void testInvokeRpcWithIdentifier() throws Exception {
+        final AtomicReference<AssertionError> assertError = new AtomicReference<>();
+        try {
+            RemoteRpcImplementation rpcImpl = new RemoteRpcImplementation(
+                    probeReg1.getRef(), schemaContext);
+
+            QName instanceQName = new QName(new URI("ns"), "instance");
+            YangInstanceIdentifier identifier = YangInstanceIdentifier.of(instanceQName);
+
+            CompositeNode input = makeRPCInput("foo");
+            CompositeNode output = makeRPCOutput("bar");
+            final AtomicReference<InvokeRpc> invokeRpcMsg = setupInvokeRpcReply(assertError, output);
+
+            ListenableFuture<RpcResult<CompositeNode>> future = rpcImpl.invokeRpc(
+                    TEST_RPC, identifier, input);
+
+            RpcResult<CompositeNode> rpcResult = future.get(5, TimeUnit.SECONDS);
+
+            assertSuccessfulRpcResult(rpcResult, (CompositeNode)output.getValue().get(0));
+
+            assertEquals("getRpc", TEST_RPC, invokeRpcMsg.get().getRpc());
+            assertEquals("getInput", input, invokeRpcMsg.get().getInput());
+            assertEquals("getRoute", identifier, invokeRpcMsg.get().getIdentifier());
+        } finally {
+            if(assertError.get() != null) {
+                throw assertError.get();
+            }
+        }
+    }
+
+    @Test
+    public void testInvokeRpcWithRpcErrorsException() throws Exception {
+        final AtomicReference<AssertionError> assertError = new AtomicReference<>();
+        try {
+            RemoteRpcImplementation rpcImpl = new RemoteRpcImplementation(
+                    probeReg1.getRef(), schemaContext);
+
+            final CompositeNode input = makeRPCInput("foo");
+
+            setupInvokeRpcErrorReply(assertError, new RpcErrorsException(
+                    "mock", Arrays.asList(RpcResultBuilder.newError(ErrorType.RPC, "tag",
+                            "error", "appTag", "info", null))));
+
+            ListenableFuture<RpcResult<CompositeNode>> future = rpcImpl.invokeRpc(TEST_RPC, input);
+
+            RpcResult<CompositeNode> rpcResult = future.get(5, TimeUnit.SECONDS);
+
+            assertFailedRpcResult(rpcResult, ErrorSeverity.ERROR, ErrorType.RPC, "tag",
+                    "error", "appTag", "info", null);
+        } finally {
+            if(assertError.get() != null) {
+                throw assertError.get();
+            }
+        }
+    }
+
+    @Test
+    public void testInvokeRpcWithOtherException() throws Exception {
+        final AtomicReference<AssertionError> assertError = new AtomicReference<>();
+        try {
+            RemoteRpcImplementation rpcImpl = new RemoteRpcImplementation(
+                    probeReg1.getRef(), schemaContext);
+
+            final CompositeNode input = makeRPCInput("foo");
+
+            setupInvokeRpcErrorReply(assertError, new TestException());
+
+            ListenableFuture<RpcResult<CompositeNode>> future = rpcImpl.invokeRpc(TEST_RPC, input);
+
+            RpcResult<CompositeNode> rpcResult = future.get(5, TimeUnit.SECONDS);
+
+            assertFailedRpcResult(rpcResult, ErrorSeverity.ERROR, ErrorType.RPC, "operation-failed",
+                    TestException.MESSAGE, null, null, TestException.MESSAGE);
+        } finally {
+            if(assertError.get() != null) {
+                throw assertError.get();
+            }
+        }
+    }
+
+    private AtomicReference<InvokeRpc> setupInvokeRpcReply(
+            final AtomicReference<AssertionError> assertError, final CompositeNode output) {
+        return setupInvokeRpcReply(assertError, output, null);
+    }
+
+    private AtomicReference<InvokeRpc> setupInvokeRpcErrorReply(
+            final AtomicReference<AssertionError> assertError, final Exception error) {
+        return setupInvokeRpcReply(assertError, null, error);
+    }
+
+    private AtomicReference<InvokeRpc> setupInvokeRpcReply(
+            final AtomicReference<AssertionError> assertError, final CompositeNode output,
+            final Exception error) {
+        final AtomicReference<InvokeRpc> invokeRpcMsg = new AtomicReference<>();
+
+        new Thread() {
+            @Override
+            public void run() {
+                try {
+                    invokeRpcMsg.set(probeReg1.expectMsgClass(
+                            JavaTestKit.duration("5 seconds"), InvokeRpc.class));
+
+                    if(output != null) {
+                        probeReg1.reply(new RpcResponse(XmlUtils.outputCompositeNodeToXml(
+                                output, schemaContext)));
+                    } else {
+                        probeReg1.reply(new akka.actor.Status.Failure(error));
+                    }
+
+                } catch(AssertionError e) {
+                    assertError.set(e);
+                }
+            }
+
+        }.start();
+
+        return invokeRpcMsg;
+    }
+}
index 17ad237ad7e4302065c08ff8796a058cd78d7885..8a7e4a039846205846e1b54b21981f78af843783 100644 (file)
@@ -14,8 +14,8 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
 import akka.testkit.JavaTestKit;
 import com.typesafe.config.ConfigFactory;
-import junit.framework.Assert;
 import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.sal.core.api.Broker;
@@ -25,7 +25,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import scala.concurrent.Await;
 import scala.concurrent.duration.Duration;
 
-
 import java.util.concurrent.TimeUnit;
 
 import static org.mockito.Mockito.mock;
@@ -38,7 +37,7 @@ public class RemoteRpcProviderTest {
 
   @BeforeClass
   public static void setup() throws InterruptedException {
-    system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster"));
+    system = ActorSystem.create("odl-cluster-rpc", ConfigFactory.load().getConfig("odl-cluster-rpc"));
   }
 
   @AfterClass
@@ -59,7 +58,4 @@ public class RemoteRpcProviderTest {
         Duration.create(2, TimeUnit.SECONDS));
     Assert.assertTrue(actorRef.path().toString().contains(ActorConstants.RPC_MANAGER_PATH));
   }
-
-
-
 }
index 9b6215addd841633cf1dd57ce42c635d1dae89b7..98a33bf4e64a680adcc40d2dd3e92823a86c5fb6 100644 (file)
@@ -32,7 +32,7 @@ public class RouteRpcListenerTest {
 
   @BeforeClass
   public static void setup() throws InterruptedException {
-    system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster"));
+    system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster-rpc"));
   }
 
   @AfterClass
index d9a3b6a414f1666dfa3b062cf7faa54c0baed8c0..28b1b476cd0ebc4d20585b58a91877c076caf33c 100644 (file)
@@ -10,144 +10,268 @@ package org.opendaylight.controller.remote.rpc;
 
 
 import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
 import akka.japi.Pair;
 import akka.testkit.JavaTestKit;
+
+import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.Futures;
-import com.typesafe.config.ConfigFactory;
-import junit.framework.Assert;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
+import static org.junit.Assert.assertEquals;
 import org.junit.Test;
-import org.mockito.Mockito;
-import org.opendaylight.controller.remote.rpc.messages.ErrorResponse;
+import org.mockito.ArgumentCaptor;
+import org.opendaylight.controller.remote.rpc.messages.ExecuteRpc;
 import org.opendaylight.controller.remote.rpc.messages.InvokeRpc;
 import org.opendaylight.controller.remote.rpc.messages.RpcResponse;
 import org.opendaylight.controller.remote.rpc.registry.RpcRegistry;
-import org.opendaylight.controller.sal.common.util.Rpcs;
-import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRouters;
+import org.opendaylight.controller.sal.connector.api.RpcRouter.RouteIdentifier;
+import org.opendaylight.controller.xml.codec.XmlUtils;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
 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.api.ModifyAction;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.Future;
 
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.any;
+
+public class RpcBrokerTest extends AbstractRpcTest {
+
+    @Test
+    public void testInvokeRpcWithNoRemoteActor() throws Exception {
+        new JavaTestKit(node1) {{
+            CompositeNode input = makeRPCInput("foo");
+
+            InvokeRpc invokeMsg = new InvokeRpc(TEST_RPC, null, input);
+            rpcBroker1.tell(invokeMsg, getRef());
+
+            probeReg1.expectMsgClass(duration("5 seconds"), RpcRegistry.Messages.FindRouters.class);
+            probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(
+                    Collections.<Pair<ActorRef, Long>>emptyList()));
+
+            akka.actor.Status.Failure failure = expectMsgClass(duration("5 seconds"),
+                    akka.actor.Status.Failure.class);
+
+            assertEquals("failure.cause()", RpcErrorsException.class, failure.cause().getClass());
+        }};
+    }
+
+
+    /**
+     * This test method invokes and executes the remote rpc
+     */
+    //@Test
+    public void testInvokeRpc() throws URISyntaxException {
+        new JavaTestKit(node1) {{
+            QName instanceQName = new QName(new URI("ns"), "instance");
+
+            CompositeNode invokeRpcResult = makeRPCOutput("bar");
+            RpcResult<CompositeNode> rpcResult =
+                               RpcResultBuilder.<CompositeNode>success(invokeRpcResult).build();
+            ArgumentCaptor<CompositeNode> inputCaptor = new ArgumentCaptor<>();
+            when(brokerSession.rpc(eq(TEST_RPC), inputCaptor.capture()))
+                    .thenReturn(Futures.immediateFuture(rpcResult));
+
+            // invoke rpc
+            CompositeNode input = makeRPCInput("foo");
+            YangInstanceIdentifier instanceID = YangInstanceIdentifier.of(instanceQName);
+            InvokeRpc invokeMsg = new InvokeRpc(TEST_RPC, instanceID, input);
+            rpcBroker1.tell(invokeMsg, getRef());
+
+            FindRouters findRouters = probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class);
+            RouteIdentifier<?, ?, ?> routeIdentifier = findRouters.getRouteIdentifier();
+            assertEquals("getType", TEST_RPC, routeIdentifier.getType());
+            assertEquals("getRoute", instanceID, routeIdentifier.getRoute());
+
+            probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(
+                    Arrays.asList(new Pair<ActorRef, Long>(rpcBroker2, 200L))));
+
+            RpcResponse rpcResponse = expectMsgClass(duration("5 seconds"), RpcResponse.class);
+            assertCompositeNodeEquals((CompositeNode)invokeRpcResult.getValue().get(0),
+                    XmlUtils.xmlToCompositeNode(rpcResponse.getResultCompositeNode()));
+            assertCompositeNodeEquals(input, inputCaptor.getValue());
+        }};
+    }
+
+    @Test
+    public void testInvokeRpcWithNoOutput() {
+        new JavaTestKit(node1) {{
+
+            RpcResult<CompositeNode> rpcResult = RpcResultBuilder.<CompositeNode>success().build();
+            when(brokerSession.rpc(eq(TEST_RPC), any(CompositeNode.class)))
+                    .thenReturn(Futures.immediateFuture(rpcResult));
+
+            InvokeRpc invokeMsg = new InvokeRpc(TEST_RPC, null, makeRPCInput("foo"));
+            rpcBroker1.tell(invokeMsg, getRef());
+
+            probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class);
+            probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(
+                    Arrays.asList(new Pair<ActorRef, Long>(rpcBroker2, 200L))));
+
+            RpcResponse rpcResponse = expectMsgClass(duration("5 seconds"), RpcResponse.class);
+
+            assertEquals("getResultCompositeNode", "", rpcResponse.getResultCompositeNode());
+        }};
+    }
+
+    @Test
+    public void testInvokeRpcWithExecuteFailure() {
+        new JavaTestKit(node1) {{
+
+            RpcResult<CompositeNode> rpcResult = RpcResultBuilder.<CompositeNode>failed()
+                    .withError(ErrorType.RPC, "tag", "error", "appTag", "info",
+                            new Exception("mock"))
+                    .build();
+            when(brokerSession.rpc(eq(TEST_RPC), any(CompositeNode.class)))
+                    .thenReturn(Futures.immediateFuture(rpcResult));
+
+            InvokeRpc invokeMsg = new InvokeRpc(TEST_RPC, null, makeRPCInput("foo"));
+            rpcBroker1.tell(invokeMsg, getRef());
+
+            probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class);
+            probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(
+                    Arrays.asList(new Pair<ActorRef, Long>(rpcBroker2, 200L))));
+
+            akka.actor.Status.Failure failure = expectMsgClass(duration("5 seconds"),
+                    akka.actor.Status.Failure.class);
+
+            assertEquals("failure.cause()", RpcErrorsException.class, failure.cause().getClass());
+
+            RpcErrorsException errorsEx = (RpcErrorsException)failure.cause();
+            List<RpcError> rpcErrors = Lists.newArrayList(errorsEx.getRpcErrors());
+            assertEquals("RpcErrors count", 1, rpcErrors.size());
+            assertRpcErrorEquals(rpcErrors.get(0), ErrorSeverity.ERROR, ErrorType.RPC, "tag",
+                    "error", "appTag", "info", "mock");
+        }};
+    }
+
+    @Test
+    public void testInvokeRpcWithFindRoutersFailure() {
+        new JavaTestKit(node1) {{
+
+            InvokeRpc invokeMsg = new InvokeRpc(TEST_RPC, null, makeRPCInput("foo"));
+            rpcBroker1.tell(invokeMsg, getRef());
+
+            probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class);
+            probeReg1.reply(new akka.actor.Status.Failure(new TestException()));
+
+            akka.actor.Status.Failure failure = expectMsgClass(duration("5 seconds"),
+                    akka.actor.Status.Failure.class);
+
+            assertEquals("failure.cause()", TestException.class, failure.cause().getClass());
+        }};
+    }
+
+    @Test
+    public void testExecuteRpc() {
+        new JavaTestKit(node1) {{
+
+            String xml = "<input xmlns=\"urn:test\"><input-data>foo</input-data></input>";
+
+            CompositeNode invokeRpcResult = makeRPCOutput("bar");
+            RpcResult<CompositeNode> rpcResult =
+                               RpcResultBuilder.<CompositeNode>success(invokeRpcResult).build();
+            ArgumentCaptor<CompositeNode> inputCaptor = new ArgumentCaptor<>();
+            when(brokerSession.rpc(eq(TEST_RPC), inputCaptor.capture()))
+                    .thenReturn(Futures.immediateFuture(rpcResult));
+
+            ExecuteRpc executeMsg = new ExecuteRpc(xml, TEST_RPC);
+
+            rpcBroker1.tell(executeMsg, getRef());
+
+            RpcResponse rpcResponse = expectMsgClass(duration("5 seconds"), RpcResponse.class);
+
+            assertCompositeNodeEquals((CompositeNode)invokeRpcResult.getValue().get(0),
+                    XmlUtils.xmlToCompositeNode(rpcResponse.getResultCompositeNode()));
+        }};
+    }
+
+    @Test
+    public void testExecuteRpcFailureWithRpcErrors() {
+        new JavaTestKit(node1) {{
+
+            String xml = "<input xmlns=\"urn:test\"><input-data>foo</input-data></input>";
+
+            RpcResult<CompositeNode> rpcResult = RpcResultBuilder.<CompositeNode>failed()
+                    .withError(ErrorType.RPC, "tag1", "error", "appTag1", "info1",
+                            new Exception("mock"))
+                    .withWarning(ErrorType.PROTOCOL, "tag2", "warning", "appTag2", "info2", null)
+                    .build();
+            when(brokerSession.rpc(eq(TEST_RPC), any(CompositeNode.class)))
+                    .thenReturn(Futures.immediateFuture(rpcResult));
+
+            ExecuteRpc executeMsg = new ExecuteRpc(xml, TEST_RPC);
+
+            rpcBroker1.tell(executeMsg, getRef());
+
+            akka.actor.Status.Failure failure = expectMsgClass(duration("5 seconds"),
+                    akka.actor.Status.Failure.class);
+
+            assertEquals("failure.cause()", RpcErrorsException.class, failure.cause().getClass());
+
+            RpcErrorsException errorsEx = (RpcErrorsException)failure.cause();
+            List<RpcError> rpcErrors = Lists.newArrayList(errorsEx.getRpcErrors());
+            assertEquals("RpcErrors count", 2, rpcErrors.size());
+            assertRpcErrorEquals(rpcErrors.get(0), ErrorSeverity.ERROR, ErrorType.RPC, "tag1",
+                    "error", "appTag1", "info1", "mock");
+            assertRpcErrorEquals(rpcErrors.get(1), ErrorSeverity.WARNING, ErrorType.PROTOCOL, "tag2",
+                    "warning", "appTag2", "info2", null);
+        }};
+    }
+
+    @Test
+    public void testExecuteRpcFailureWithNoRpcErrors() {
+        new JavaTestKit(node1) {{
+
+            String xml = "<input xmlns=\"urn:test\"><input-data>foo</input-data></input>";
+
+            RpcResult<CompositeNode> rpcResult = RpcResultBuilder.<CompositeNode>failed().build();
+            when(brokerSession.rpc(eq(TEST_RPC), any(CompositeNode.class)))
+                    .thenReturn(Futures.immediateFuture(rpcResult));
+
+            ExecuteRpc executeMsg = new ExecuteRpc(xml, TEST_RPC);
+
+            rpcBroker1.tell(executeMsg, getRef());
+
+            akka.actor.Status.Failure failure = expectMsgClass(duration("5 seconds"),
+                    akka.actor.Status.Failure.class);
+
+            assertEquals("failure.cause()", RpcErrorsException.class, failure.cause().getClass());
+
+            RpcErrorsException errorsEx = (RpcErrorsException)failure.cause();
+            List<RpcError> rpcErrors = Lists.newArrayList(errorsEx.getRpcErrors());
+            assertEquals("RpcErrors count", 1, rpcErrors.size());
+            assertRpcErrorEquals(rpcErrors.get(0), ErrorSeverity.ERROR, ErrorType.RPC,
+                    "operation-failed", "failed", null, null, null);
+        }};
+    }
+
+    @Test
+    public void testExecuteRpcFailureWithException() {
+        new JavaTestKit(node1) {{
+
+            String xml = "<input xmlns=\"urn:test\"><input-data>foo</input-data></input>";
+
+            when(brokerSession.rpc(eq(TEST_RPC), any(CompositeNode.class)))
+                    .thenReturn(Futures.<RpcResult<CompositeNode>>immediateFailedFuture(
+                            new TestException()));
+
+            ExecuteRpc executeMsg = new ExecuteRpc(xml, TEST_RPC);
+
+            rpcBroker1.tell(executeMsg, getRef());
+
+            akka.actor.Status.Failure failure = expectMsgClass(duration("5 seconds"),
+                    akka.actor.Status.Failure.class);
 
-public class RpcBrokerTest {
-
-  static ActorSystem node1;
-  static ActorSystem node2;
-  private ActorRef rpcBroker1;
-  private JavaTestKit probeReg1;
-  private ActorRef rpcBroker2;
-  private JavaTestKit probeReg2;
-  private Broker.ProviderSession brokerSession;
-
-
-  @BeforeClass
-  public static void setup() throws InterruptedException {
-    node1 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberA"));
-    node2 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberB"));
-  }
-
-  @AfterClass
-  public static void teardown() {
-    JavaTestKit.shutdownActorSystem(node1);
-    JavaTestKit.shutdownActorSystem(node2);
-    node1 = null;
-    node2 = null;
-  }
-
-  @Before
-  public void createActor() {
-    brokerSession = Mockito.mock(Broker.ProviderSession.class);
-    SchemaContext schemaContext = mock(SchemaContext.class);
-    probeReg1 = new JavaTestKit(node1);
-    rpcBroker1 = node1.actorOf(RpcBroker.props(brokerSession, probeReg1.getRef(), schemaContext));
-    probeReg2 = new JavaTestKit(node2);
-    rpcBroker2 = node2.actorOf(RpcBroker.props(brokerSession, probeReg2.getRef(), schemaContext));
-
-  }
-  @Test
-  public void testInvokeRpcError() throws Exception {
-    new JavaTestKit(node1) {{
-      QName rpc = new QName(new URI("noactor1"), "noactor1");
-      CompositeNode input = new ImmutableCompositeNode(QName.create("ns", "2013-12-09", "no child"), new ArrayList<Node<?>>(), ModifyAction.REPLACE);
-
-
-      InvokeRpc invokeMsg = new InvokeRpc(rpc, null, input);
-      rpcBroker1.tell(invokeMsg, getRef());
-      probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class);
-      probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(new ArrayList<Pair<ActorRef, Long>>()));
-
-      Boolean getMsg = new ExpectMsg<Boolean>("ErrorResponse") {
-        protected Boolean match(Object in) {
-          if (in instanceof ErrorResponse) {
-            ErrorResponse reply = (ErrorResponse)in;
-            return reply.getException().getMessage().contains("No remote actor found for rpc execution of :");
-          } else {
-            throw noMatch();
-          }
-        }
-      }.get(); // this extracts the received message
-
-      Assert.assertTrue(getMsg);
-
-    }};
-  }
-
-
-  /**
-   * This test method invokes and executes the remote rpc
-   */
-
-  @Test
-  public void testInvokeRpc() throws URISyntaxException {
-    new JavaTestKit(node1) {{
-      QName rpc = new QName(new URI("noactor1"), "noactor1");
-      // invoke rpc
-      CompositeNode input = new ImmutableCompositeNode(QName.create("ns", "2013-12-09", "child1"), new ArrayList<Node<?>>(), ModifyAction.REPLACE);
-      InvokeRpc invokeMsg = new InvokeRpc(rpc, null, input);
-      rpcBroker1.tell(invokeMsg, getRef());
-
-      probeReg1.expectMsgClass(RpcRegistry.Messages.FindRouters.class);
-      List<Pair<ActorRef, Long>> routerList = new ArrayList<Pair<ActorRef, Long>>();
-
-      routerList.add(new Pair<ActorRef, Long>(rpcBroker2, 200L));
-
-      probeReg1.reply(new RpcRegistry.Messages.FindRoutersReply(routerList));
-
-      CompositeNode invokeRpcResult = mock(CompositeNode.class);
-      Collection<RpcError> errors = new ArrayList<>();
-      RpcResult<CompositeNode> result = Rpcs.getRpcResult(true, invokeRpcResult, errors);
-      Future<RpcResult<CompositeNode>> rpcResult = Futures.immediateFuture(result);
-      when(brokerSession.rpc(rpc, input)).thenReturn(rpcResult);
-
-      //verify response msg
-      Boolean getMsg = new ExpectMsg<Boolean>("RpcResponse") {
-        protected Boolean match(Object in) {
-          if (in instanceof RpcResponse) {
-            return true;
-          } else {
-            throw noMatch();
-          }
-        }
-      }.get(); // this extracts the received message
-
-      Assert.assertTrue(getMsg);
-    }};
-  }
+            assertEquals("failure.cause()", TestException.class, failure.cause().getClass());
+        }};
+    }
 }
index 7b5a968866ca1ecca306b42fc09d76b0a6aaf20a..956e1599904ccc52303ff380892bc3531861cd5b 100644 (file)
@@ -28,7 +28,7 @@ public class RpcListenerTest {
 
   @BeforeClass
   public static void setup() throws InterruptedException {
-    system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster"));
+    system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster-rpc"));
   }
 
   @AfterClass
index e6793741a3ec2ef9030a2e469058ab92de93c153..83f52930b2b07ac32c75f83f437f1048132b54df 100644 (file)
@@ -10,10 +10,8 @@ import akka.actor.Props;
 import akka.testkit.JavaTestKit;
 import com.google.common.base.Predicate;
 import com.typesafe.config.ConfigFactory;
-
 import org.junit.After;
 import org.junit.AfterClass;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -22,8 +20,6 @@ import org.opendaylight.controller.remote.rpc.registry.gossip.Messages;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.utils.ConditionalProbe;
 import org.opendaylight.yangtools.yang.common.QName;
-import scala.concurrent.Await;
-import scala.concurrent.Future;
 import scala.concurrent.duration.FiniteDuration;
 
 import javax.annotation.Nullable;
@@ -33,9 +29,9 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoutes;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.RemoveRoutes;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
 
 public class RpcRegistryTest {
 
@@ -95,7 +91,6 @@ public class RpcRegistryTest {
    */
   @Test
   public void testAddRemoveRpcOnSameNode() throws URISyntaxException, InterruptedException {
-    validateSystemStartup();
 
     final JavaTestKit mockBroker = new JavaTestKit(node1);
 
@@ -137,8 +132,6 @@ public class RpcRegistryTest {
   @Test
   public void testRpcAddRemoveInCluster() throws URISyntaxException, InterruptedException {
 
-    validateSystemStartup();
-
     final JavaTestKit mockBroker1 = new JavaTestKit(node1);
 
     //install probe on node2's bucket store
@@ -146,7 +139,6 @@ public class RpcRegistryTest {
     final JavaTestKit probe2 = createProbeForMessage(
         node2, bucketStorePath, Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
 
-
     //Add rpc on node 1
     registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
     registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
@@ -175,8 +167,6 @@ public class RpcRegistryTest {
   @Test
   public void testRpcAddedOnMultiNodes() throws Exception {
 
-    validateSystemStartup();
-
     final JavaTestKit mockBroker1 = new JavaTestKit(node1);
     final JavaTestKit mockBroker2 = new JavaTestKit(node2);
     final JavaTestKit mockBroker3 = new JavaTestKit(node3);
@@ -225,49 +215,6 @@ public class RpcRegistryTest {
 
   }
 
-  private void validateSystemStartup() throws InterruptedException {
-
-    ActorPath gossiper1Path = new ChildActorPath(new ChildActorPath(registry1.path(), "store"), "gossiper");
-    ActorPath gossiper2Path = new ChildActorPath(new ChildActorPath(registry2.path(), "store"), "gossiper");
-    ActorPath gossiper3Path = new ChildActorPath(new ChildActorPath(registry3.path(), "store"), "gossiper");
-
-    ActorSelection gossiper1 = node1.actorSelection(gossiper1Path);
-    ActorSelection gossiper2 = node2.actorSelection(gossiper2Path);
-    ActorSelection gossiper3 = node3.actorSelection(gossiper3Path);
-
-
-    if (!resolveReference(gossiper1, gossiper2, gossiper3))
-      Assert.fail("Could not find gossipers");
-  }
-
-  private Boolean resolveReference(ActorSelection... gossipers) {
-
-    Boolean resolved = true;
-    for (int i = 0; i < 5; i++) {
-
-      resolved = true;
-      System.out.println(System.currentTimeMillis() + " Resolving gossipers; trial #" + i);
-
-      for (ActorSelection gossiper : gossipers) {
-        ActorRef ref = null;
-
-        try {
-          Future<ActorRef> future = gossiper.resolveOne(new FiniteDuration(15000, TimeUnit.MILLISECONDS));
-          ref = Await.result(future, new FiniteDuration(10000, TimeUnit.MILLISECONDS));
-        } catch (Exception e) {
-          System.out.println("Could not find gossiper in attempt#" + i + ". Got exception " + e.getMessage());
-        }
-
-        if (ref == null)
-          resolved = false;
-      }
-
-      if (resolved) break;
-
-    }
-    return resolved;
-  }
-
   private AddOrUpdateRoutes getAddRouteMessage() throws URISyntaxException {
     return new AddOrUpdateRoutes(createRouteIds());
   }
index b21f0f0069e3db4d62a7e024c7c3d5ff513067d2..cd031a1d0abcf330b3c63c90a576b65dc2cd2d1d 100644 (file)
@@ -30,7 +30,7 @@ public class LatestEntryRoutingLogicTest {
 
   @BeforeClass
   public static void setup() throws InterruptedException {
-    system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster"));
+    system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster-rpc"));
   }
 
   @AfterClass
index 8100ed35abd580a13367922ff255e42c61369f93..5c4af8d3da457c99344c0a26942c9d3456694f75 100644 (file)
@@ -1,6 +1,12 @@
-odl-cluster{
+odl-cluster-rpc{
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 10ms
+  }
+
   akka {
-    loglevel = "DEBUG"
+    loglevel = "INFO"
     #log-config-on-start = on
 
     actor {
@@ -34,12 +40,22 @@ unit-test{
     loglevel = "INFO"
     #loggers = ["akka.event.slf4j.Slf4jLogger"]
   }
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 10ms
+  }
 }
 
 memberA{
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 10ms
+  }
   akka {
     loglevel = "INFO"
-    loggers = ["akka.event.slf4j.Slf4jLogger"]
+    #loggers = ["akka.event.slf4j.Slf4jLogger"]
     actor {
       provider = "akka.cluster.ClusterActorRefProvider"
       debug {
@@ -65,11 +81,20 @@ memberA{
   }
 }
 memberB{
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 10ms
+  }
   akka {
     loglevel = "INFO"
-    loggers = ["akka.event.slf4j.Slf4jLogger"]
+    #loggers = ["akka.event.slf4j.Slf4jLogger"]
+
     actor {
       provider = "akka.cluster.ClusterActorRefProvider"
+      debug {
+        #lifecycle = on
+      }
     }
     remote {
       log-received-messages = off
@@ -90,11 +115,19 @@ memberB{
   }
 }
 memberC{
+  bounded-mailbox {
+    mailbox-type = "org.opendaylight.controller.common.actor.MeteredBoundedMailbox"
+    mailbox-capacity = 1000
+    mailbox-push-timeout-time = 10ms
+  }
   akka {
     loglevel = "INFO"
-    loggers = ["akka.event.slf4j.Slf4jLogger"]
+    #loggers = ["akka.event.slf4j.Slf4jLogger"]
     actor {
       provider = "akka.cluster.ClusterActorRefProvider"
+      debug {
+        #lifecycle = on
+      }
     }
     remote {
       log-received-messages = off
@@ -113,4 +146,5 @@ memberC{
       auto-down-unreachable-after = 10s
     }
   }
-}
\ No newline at end of file
+}
+
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/test-rpc.yang b/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/test-rpc.yang
new file mode 100644 (file)
index 0000000..3474e91
--- /dev/null
@@ -0,0 +1,24 @@
+module test-rpc-service {
+    yang-version 1;
+    namespace "urn:test";
+    prefix "rpc";
+
+    revision "2014-08-28" {
+        description 
+            "Initial revision";
+    }
+
+    rpc test-rpc {
+        input {
+            leaf input-data {
+                type string;
+            }
+        }
+        
+        output {
+            leaf output-data {
+                type string;
+            }
+        }
+    }
+}
\ No newline at end of file
index e61cafa70b40c83f922460572ee232f5043ed4ea..fe5c9f39d8251e903c1ed5d9f173ced7df5f0f5b 100644 (file)
       <artifactId>jaxrs-api</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-core-spi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-composite-node</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-codec-gson</artifactId>
+    </dependency>
+
     <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-core-spi</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
-      <artifactId>yang-data-composite-node</artifactId>
-      <version>0.6.2-SNAPSHOT</version>
-    </dependency>
   </dependencies>
 
   <build>
index 52115a8f32f5ca5c04a5fb0d7c994456cc114544..fe20e3a441590b14f658d025567102977dd97d51 100644 (file)
@@ -1,10 +1,12 @@
 package org.opendaylight.controller.config.yang.md.sal.rest.connector;
 
-import org.opendaylight.controller.sal.rest.impl.RestconfProviderImpl;
+import org.opendaylight.controller.sal.restconf.impl.RestconfProviderImpl;
 
 
 public class RestConnectorModule extends org.opendaylight.controller.config.yang.md.sal.rest.connector.AbstractRestConnectorModule {
 
+    private static RestConnectorRuntimeRegistration runtimeRegistration;
+
     public RestConnectorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
@@ -26,6 +28,14 @@ public class RestConnectorModule extends org.opendaylight.controller.config.yang
         instance.setWebsocketPort(getWebsocketPort());
         // Register it with the Broker
         getDomBrokerDependency().registerProvider(instance);
+
+        if(runtimeRegistration != null){
+            runtimeRegistration.close();
+        }
+
+        runtimeRegistration =
+            getRootRuntimeBeanRegistratorWrapper().register(instance);
+
         return instance;
     }
 }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfConstants.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfConstants.java
new file mode 100644 (file)
index 0000000..1ec1c29
--- /dev/null
@@ -0,0 +1,7 @@
+package org.opendaylight.controller.sal.rest.api;
+
+public interface RestconfConstants {
+
+
+    public static String IDENTIFIER = "identifier";
+}
index 9c149a21e60e70ff88c0371e936e3844c05b5985..4a46a3c26712c8e54da6650bd4e68b2de9ad91ca 100644 (file)
@@ -21,10 +21,12 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
+import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
 import org.opendaylight.controller.sal.restconf.impl.StructuredData;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
 
+
 /**
  * The URI hierarchy for the RESTCONF resources consists of an entry point container, 4 top-level resources, and 1
  * field.
@@ -109,14 +111,14 @@ public interface RestconfService {
     @Path("/config/{identifier:.+}")
     @Produces({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
             MediaType.APPLICATION_XML, MediaType.TEXT_XML })
-    public StructuredData readConfigurationData(@Encoded @PathParam("identifier") String identifier,
+    public NormalizedNodeContext readConfigurationData(@Encoded @PathParam("identifier") String identifier,
             @Context UriInfo uriInfo);
 
     @GET
     @Path("/operational/{identifier:.+}")
     @Produces({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
             MediaType.APPLICATION_XML, MediaType.TEXT_XML })
-    public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier,
+    public NormalizedNodeContext readOperationalData(@Encoded @PathParam("identifier") String identifier,
             @Context UriInfo uriInfo);
 
     @PUT
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/AbstractIdentifierAwareJaxRsProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/AbstractIdentifierAwareJaxRsProvider.java
new file mode 100644 (file)
index 0000000..978ae0d
--- /dev/null
@@ -0,0 +1,30 @@
+package org.opendaylight.controller.sal.rest.impl;
+
+import com.google.common.base.Optional;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.controller.sal.rest.api.RestconfConstants;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
+
+public class AbstractIdentifierAwareJaxRsProvider {
+
+    @Context
+    private UriInfo uriInfo;
+
+    protected final String getIdentifier() {
+        return uriInfo.getPathParameters().getFirst(RestconfConstants.IDENTIFIER);
+    }
+
+    protected final Optional<InstanceIdentifierContext> getIdentifierWithSchema() {
+        return Optional.of(getInstanceIdentifierContext());
+    }
+
+    protected InstanceIdentifierContext getInstanceIdentifierContext() {
+        return ControllerContext.getInstance().toInstanceIdentifier(getIdentifier());
+    }
+
+    protected UriInfo getUriInfo() {
+        return uriInfo;
+    }
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java
new file mode 100644 (file)
index 0000000..dc989d2
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl;
+
+import com.google.common.base.Optional;
+import com.google.gson.stream.JsonReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import org.opendaylight.controller.sal.rest.api.Draft02;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
+import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Provider
+@Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
+        MediaType.APPLICATION_JSON })
+public class JsonNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsProvider implements MessageBodyReader<NormalizedNodeContext> {
+
+    private final static Logger LOG = LoggerFactory.getLogger(JsonNormalizedNodeBodyReader.class);
+
+    @Override
+    public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType) {
+        return true;
+    }
+
+    @Override
+    public NormalizedNodeContext readFrom(final Class<NormalizedNodeContext> type, final Type genericType,
+            final Annotation[] annotations, final MediaType mediaType,
+            final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws IOException,
+            WebApplicationException {
+        try {
+            Optional<InstanceIdentifierContext> path = getIdentifierWithSchema();
+            NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+            NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+            JsonParserStream jsonParser = JsonParserStream.create(writer, path.get().getSchemaContext());
+            JsonReader reader = new JsonReader(new InputStreamReader(entityStream));
+            jsonParser.parse(reader);
+            return new NormalizedNodeContext(path.get(),resultHolder.getResult());
+        } catch (Exception e) {
+            LOG.debug("Error parsing json input", e);
+
+            throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
+                    ErrorTag.MALFORMED_MESSAGE);
+        }
+    }
+}
+
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeJsonBodyWriter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeJsonBodyWriter.java
new file mode 100644 (file)
index 0000000..cfb5e5d
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl;
+
+import com.google.common.base.Charsets;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.util.Iterator;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import org.opendaylight.controller.sal.rest.api.Draft02;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
+import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+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.MapEntryNode;
+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.codec.gson.JSONNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@Provider
+@Produces({ Draft02.MediaTypes.API + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON,
+    Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON })
+public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<NormalizedNodeContext> {
+
+    @Override
+    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
+        return type.equals(NormalizedNodeContext.class);
+    }
+
+    @Override
+    public long getSize(final NormalizedNodeContext t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
+        return -1;
+    }
+
+    @Override
+    public void writeTo(final NormalizedNodeContext t, final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
+                    throws IOException, WebApplicationException {
+        NormalizedNode<?, ?> data = t.getData();
+        InstanceIdentifierContext context = t.getInstanceIdentifierContext();
+        DataSchemaNode schema = context.getSchemaNode();
+        SchemaPath path = context.getSchemaNode().getPath();
+        OutputStreamWriter outputWriter = new OutputStreamWriter(entityStream, Charsets.UTF_8);
+        if (data == null) {
+            throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
+        }
+
+        boolean isDataRoot = false;
+        URI initialNs = null;
+        outputWriter.write('{');
+        if (SchemaPath.ROOT.equals(path)) {
+            isDataRoot = true;
+        } else {
+            path = path.getParent();
+            // FIXME: Add proper handling of reading root.
+        }
+        if(!schema.isAugmenting() && !(schema instanceof SchemaContext)) {
+            initialNs = schema.getQName().getNamespace();
+        }
+        NormalizedNodeStreamWriter jsonWriter = JSONNormalizedNodeStreamWriter.create(context.getSchemaContext(),path,initialNs,outputWriter);
+        NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(jsonWriter);
+        if(isDataRoot) {
+            writeDataRoot(outputWriter,nnWriter,(ContainerNode) data);
+        } else {
+            if(data instanceof MapEntryNode) {
+                data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).withChild(((MapEntryNode) data)).build();
+            }
+            nnWriter.write(data);
+        }
+        nnWriter.flush();
+        outputWriter.write('}');
+        outputWriter.flush();
+    }
+
+    private void writeDataRoot(OutputStreamWriter outputWriter, NormalizedNodeWriter nnWriter, ContainerNode data) throws IOException {
+        Iterator<DataContainerChild<? extends PathArgument, ?>> iterator = data.getValue().iterator();
+        while(iterator.hasNext()) {
+            DataContainerChild<? extends PathArgument, ?> child = iterator.next();
+            nnWriter.write(child);
+            nnWriter.flush();
+            if(iterator.hasNext()) {
+                outputWriter.write(",");
+            }
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java
new file mode 100644 (file)
index 0000000..3a6de30
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl;
+
+import com.google.common.base.Throwables;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.controller.sal.rest.api.Draft02;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
+import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.QName;
+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.MapEntryNode;
+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.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@Provider
+@Produces({ Draft02.MediaTypes.API + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML,
+        Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+public class NormalizedNodeXmlBodyWriter implements MessageBodyWriter<NormalizedNodeContext> {
+
+    private static final XMLOutputFactory XML_FACTORY;
+
+    static {
+        XML_FACTORY = XMLOutputFactory.newFactory();
+        XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+    }
+
+    @Override
+    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType) {
+        return type.equals(NormalizedNodeContext.class);
+    }
+
+    @Override
+    public long getSize(final NormalizedNodeContext t, final Class<?> type, final Type genericType,
+            final Annotation[] annotations, final MediaType mediaType) {
+        return -1;
+    }
+
+    @Override
+    public void writeTo(final NormalizedNodeContext t, final Class<?> type, final Type genericType,
+            final Annotation[] annotations, final MediaType mediaType,
+            final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws IOException,
+            WebApplicationException {
+        InstanceIdentifierContext pathContext = t.getInstanceIdentifierContext();
+        if (t.getData() == null) {
+            throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
+        }
+
+        XMLStreamWriter xmlWriter;
+        try {
+            xmlWriter = XML_FACTORY.createXMLStreamWriter(entityStream);
+        } catch (XMLStreamException e) {
+            throw new IllegalStateException(e);
+        } catch (FactoryConfigurationError e) {
+            throw new IllegalStateException(e);
+        }
+        NormalizedNode<?, ?> data = t.getData();
+        SchemaPath schemaPath = pathContext.getSchemaNode().getPath();
+
+        boolean isDataRoot = false;
+        if (SchemaPath.ROOT.equals(schemaPath)) {
+            isDataRoot = true;
+        } else {
+            schemaPath = schemaPath.getParent();
+        }
+
+        NormalizedNodeStreamWriter jsonWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
+                pathContext.getSchemaContext(), schemaPath);
+        NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(jsonWriter);
+        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();
+        }
+    }
+
+    private void writeRootElement(XMLStreamWriter xmlWriter, NormalizedNodeWriter nnWriter, ContainerNode data)
+            throws IOException {
+        try {
+            QName name = SchemaContext.NAME;
+            xmlWriter.writeStartElement(name.getNamespace().toString(), name.getLocalName());
+            for (DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
+                nnWriter.write(child);
+            }
+            nnWriter.flush();
+            xmlWriter.writeEndElement();
+            xmlWriter.flush();
+        } catch (XMLStreamException e) {
+            Throwables.propagate(e);
+        }
+    }
+}
index b4b2a1f9ef7249734e128456a33876abc3862ae8..c9496af4c86d4838b6ee570e26b2b84ac8c34e26 100644 (file)
@@ -14,12 +14,19 @@ import javax.ws.rs.core.Application;
 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.controller.sal.restconf.impl.StatisticsRestconfServiceWrapper;
 
 public class RestconfApplication extends Application {
 
     @Override
     public Set<Class<?>> getClasses() {
-        return ImmutableSet.<Class<?>> of(RestconfDocumentedExceptionMapper.class);
+        return ImmutableSet.<Class<?>> builder()
+                .add(RestconfDocumentedExceptionMapper.class)
+                .add(XmlNormalizedNodeBodyReader.class)
+                .add(JsonNormalizedNodeBodyReader.class)
+                .add(NormalizedNodeJsonBodyWriter.class)
+                .add(NormalizedNodeXmlBodyWriter.class)
+                .build();
     }
 
     @Override
@@ -32,11 +39,11 @@ public class RestconfApplication extends Application {
         restconfImpl.setControllerContext(controllerContext);
         singletons.add(controllerContext);
         singletons.add(brokerFacade);
-        singletons.add(restconfImpl);
-        singletons.add(XmlToCompositeNodeProvider.INSTANCE);
+        singletons.add(StatisticsRestconfServiceWrapper.getInstance());
         singletons.add(StructuredDataToXmlProvider.INSTANCE);
-        singletons.add(JsonToCompositeNodeProvider.INSTANCE);
         singletons.add(StructuredDataToJsonProvider.INSTANCE);
+        singletons.add(JsonToCompositeNodeProvider.INSTANCE);
+        singletons.add(XmlToCompositeNodeProvider.INSTANCE);
         return singletons;
     }
 
index 933ed0f849e7171b7c16c423c5462aa8de1bb25a..063d2f51afffdd0c7094d7363d95795182b5cd8e 100644 (file)
@@ -30,27 +30,24 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 
 @Provider
 @Produces({ Draft02.MediaTypes.API + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON,
-        Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON })
+    Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON })
 public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
     @Override
-    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
-            final MediaType mediaType) {
+    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
         return type.equals(StructuredData.class);
     }
 
     @Override
-    public long getSize(final StructuredData t, final Class<?> type, final Type genericType,
-            final Annotation[] annotations, final MediaType mediaType) {
+    public long getSize(final StructuredData t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
         return -1;
     }
 
     @Override
-    public void writeTo(final StructuredData t, final Class<?> type, final Type genericType,
-            final Annotation[] annotations, final MediaType mediaType,
-            final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws IOException,
-            WebApplicationException {
+    public void writeTo(final StructuredData t, final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
+                    throws IOException, WebApplicationException {
         CompositeNode data = t.getData();
         if (data == null) {
             throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlNormalizedNodeBodyReader.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlNormalizedNodeBodyReader.java
new file mode 100644 (file)
index 0000000..062a448
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl;
+
+import com.google.common.base.Optional;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.opendaylight.controller.sal.rest.api.Draft02;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
+import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+@Provider
+@Consumes({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
+    MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+public class XmlNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsProvider implements MessageBodyReader<NormalizedNodeContext> {
+
+    private final static Logger LOG = LoggerFactory.getLogger(XmlNormalizedNodeBodyReader.class);
+    private final static DomToNormalizedNodeParserFactory DOM_PARSER_FACTORY = DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER);
+    private static final DocumentBuilderFactory BUILDERFACTORY;
+
+    static {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        factory.setCoalescing(true);
+        factory.setIgnoringElementContentWhitespace(true);
+        factory.setIgnoringComments(true);
+        BUILDERFACTORY = factory;
+    }
+
+    @Override
+    public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType) {
+        return true;
+    }
+
+    @Override
+    public NormalizedNodeContext readFrom(final Class<NormalizedNodeContext> type, final Type genericType,
+            final Annotation[] annotations, final MediaType mediaType,
+            final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws IOException,
+            WebApplicationException {
+        try {
+            Optional<InstanceIdentifierContext> path = getIdentifierWithSchema();
+
+            final DocumentBuilder dBuilder;
+            try {
+                dBuilder = BUILDERFACTORY.newDocumentBuilder();
+            } catch (ParserConfigurationException e) {
+                throw new RuntimeException("Failed to parse XML document", e);
+            }
+            Document doc = dBuilder.parse(entityStream);
+
+            NormalizedNode<?, ?> result = parse(path.get(),doc);
+            return new NormalizedNodeContext(path.get(),result);
+        } catch (Exception e) {
+            LOG.debug("Error parsing json input", e);
+
+            throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
+                    ErrorTag.MALFORMED_MESSAGE);
+        }
+    }
+
+    private static NormalizedNode<?,?> parse(InstanceIdentifierContext pathContext,Document doc) {
+        List<Element> elements = Collections.singletonList(doc.getDocumentElement());
+        DataSchemaNode schemaNode = pathContext.getSchemaNode();
+        if(schemaNode instanceof ContainerSchemaNode) {
+            return DOM_PARSER_FACTORY.getContainerNodeParser().parse(Collections.singletonList(doc.getDocumentElement()), (ContainerSchemaNode) schemaNode);
+        } else if(schemaNode instanceof ListSchemaNode) {
+            ListSchemaNode casted = (ListSchemaNode) schemaNode;
+            return DOM_PARSER_FACTORY.getMapEntryNodeParser().parse(elements, casted);
+        }
+        return null;
+    }
+}
+
index 5944d6003e9e1e33dba8a0b482a60de5f01ac4c0..6b9da80c685f913cce59edb19bc4588b16e0ed57 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
 import org.opendaylight.yangtools.yang.data.api.Node;
 
+@Deprecated
 public class XmlToCompositeNodeReader {
 
     private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
@@ -45,7 +46,6 @@ public class XmlToCompositeNodeReader {
         }
 
         eventReader = xmlInputFactory.createXMLEventReader(entityStream);
-
         if (eventReader.hasNext()) {
             XMLEvent element = eventReader.peek();
             if (element.isStartDocument()) {
@@ -110,7 +110,7 @@ public class XmlToCompositeNodeReader {
         return entityStream;
     }
 
-    private boolean isInputStreamEmpty(InputStream entityStream) throws IOException {
+    private boolean isInputStreamEmpty(final InputStream entityStream) throws IOException {
         boolean isEmpty = false;
         entityStream.mark(1);
         if (entityStream.read() == -1) {
@@ -180,7 +180,7 @@ public class XmlToCompositeNodeReader {
                 resolveValueOfElement(data, startElement));
     }
 
-    private String getValueOf(StartElement startElement) throws XMLStreamException {
+    private String getValueOf(final StartElement startElement) throws XMLStreamException {
         String data = null;
         if (eventReader.hasNext()) {
             final XMLEvent innerEvent = eventReader.peek();
@@ -201,7 +201,7 @@ public class XmlToCompositeNodeReader {
         return data == null ? null : data.trim();
     }
 
-    private String getAdditionalData(XMLEvent event) throws XMLStreamException {
+    private String getAdditionalData(final XMLEvent event) throws XMLStreamException {
         String data = "";
         if (eventReader.hasNext()) {
             final XMLEvent innerEvent = eventReader.peek();
@@ -216,16 +216,16 @@ public class XmlToCompositeNodeReader {
         return data;
     }
 
-    private String getLocalNameFor(StartElement startElement) {
+    private String getLocalNameFor(final StartElement startElement) {
         return startElement.getName().getLocalPart();
     }
 
-    private URI getNamespaceFor(StartElement startElement) {
+    private URI getNamespaceFor(final StartElement startElement) {
         String namespaceURI = startElement.getName().getNamespaceURI();
         return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
     }
 
-    private Object resolveValueOfElement(String value, StartElement startElement) {
+    private Object resolveValueOfElement(final String value, final StartElement startElement) {
         // it could be instance-identifier Built-In Type
         if (value.startsWith("/")) {
             IdentityValuesDTO iiValue = RestUtil.asInstanceIdentifier(value, new RestUtil.PrefixMapingFromXml(
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/XmlToNormalizedNodeReaderWithSchema.java
deleted file mode 100644 (file)
index 935d96c..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.rest.impl;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Stack;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamConstants;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.Characters;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
-import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
-import org.opendaylight.controller.sal.restconf.impl.NodeWrapper;
-import org.opendaylight.controller.sal.restconf.impl.RestCodec;
-import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
-import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
-import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
-import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-
-public class XmlToNormalizedNodeReaderWithSchema {
-
-    private final static XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
-    private XMLEventReader eventReader;
-    private InstanceIdWithSchemaNode iiWithSchema;
-
-    public XmlToNormalizedNodeReaderWithSchema(final InstanceIdWithSchemaNode iiWithSchema) {
-        this.iiWithSchema = iiWithSchema;
-    }
-
-    public Node<?> read(InputStream entityStream) throws XMLStreamException, UnsupportedFormatException, IOException {
-        // Get an XML stream which can be marked, and reset, so we can check and see if there is
-        // any content being provided.
-        entityStream = getMarkableStream(entityStream);
-
-        if (isInputStreamEmpty(entityStream)) {
-            return null;
-        }
-
-        eventReader = xmlInputFactory.createXMLEventReader(entityStream);
-        if (eventReader.hasNext()) {
-            XMLEvent element = eventReader.peek();
-            if (element.isStartDocument()) {
-                eventReader.nextEvent();
-            }
-        }
-
-        final Stack<NodeWrapper<?>> processingQueue = new Stack<>();
-        NodeWrapper<?> root = null;
-        NodeWrapper<?> element = null;
-        Stack<DataSchemaNode> processingQueueSchema = new Stack<>();
-
-        while (eventReader.hasNext()) {
-            final XMLEvent event = eventReader.nextEvent();
-
-            if (event.isStartElement()) {
-                final StartElement startElement = event.asStartElement();
-                CompositeNodeWrapper compParentNode = null;
-                if (!processingQueue.isEmpty() && processingQueue.peek() instanceof CompositeNodeWrapper) {
-                    compParentNode = (CompositeNodeWrapper) processingQueue.peek();
-                    findSchemaNodeForElement(startElement, processingQueueSchema);
-                } else {
-                    processingQueueSchema = checkElementAndSchemaNodeNameAndNamespace(startElement,
-                            iiWithSchema.getSchemaNode());
-                    DataSchemaNode currentSchemaNode = processingQueueSchema.peek();
-                    if (!(currentSchemaNode instanceof ListSchemaNode)
-                            && !(currentSchemaNode instanceof ContainerSchemaNode)) {
-                        throw new UnsupportedFormatException(
-                                "Top level element has to be of type list or container schema node.");
-                    }
-                }
-
-                NodeWrapper<?> newNode = null;
-                if (isCompositeNodeEvent(event)) {
-                    newNode = resolveCompositeNodeFromStartElement(processingQueueSchema.peek().getQName());
-                    if (root == null) {
-                        root = newNode;
-                    }
-                } else if (isSimpleNodeEvent(event)) {
-                    newNode = resolveSimpleNodeFromStartElement(processingQueueSchema.peek(), getValueOf(startElement));
-                    if (root == null) {
-                        root = newNode;
-                    }
-                }
-
-                if (newNode != null) {
-                    processingQueue.push(newNode);
-                    if (compParentNode != null) {
-                        compParentNode.addValue(newNode);
-                    }
-                }
-            } else if (event.isEndElement()) {
-                element = processingQueue.pop();
-//                if(((EndElement)event).getName().getLocalPart().equals
-                processingQueueSchema.pop();
-            }
-        }
-
-        if (!root.getLocalName().equals(element.getLocalName())) {
-            throw new UnsupportedFormatException("XML should contain only one root element");
-        }
-
-        return root.unwrap();
-    }
-
-    private void findSchemaNodeForElement(StartElement element, Stack<DataSchemaNode> processingQueueSchema) {
-        DataSchemaNode currentSchemaNode = processingQueueSchema.peek();
-        if (currentSchemaNode instanceof DataNodeContainer) {
-            final URI realNamespace = getNamespaceFor(element);
-            final String realName = getLocalNameFor(element);
-            Map<URI, DataSchemaNode> childNamesakes = resolveChildsWithNameAsElement(
-                    ((DataNodeContainer) currentSchemaNode), realName);
-            DataSchemaNode childDataSchemaNode = childNamesakes.get(realNamespace);
-            if (childDataSchemaNode == null) {
-                throw new RestconfDocumentedException("Element " + realName + " has namespace " + realNamespace
-                        + ". Available namespaces are: " + childNamesakes.keySet(), ErrorType.APPLICATION,
-                        ErrorTag.INVALID_VALUE);
-            }
-            processingQueueSchema.push(childDataSchemaNode);
-        } else {
-            throw new RestconfDocumentedException("Element " + processingQueueSchema.peek().getQName().getLocalName()
-                    + " should be data node container .", ErrorType.APPLICATION, ErrorTag.INVALID_VALUE);
-        }
-
-    }
-
-    /**
-     * Returns map of data schema node which are accesible by URI which have equal name
-     */
-    private Map<URI, DataSchemaNode> resolveChildsWithNameAsElement(final DataNodeContainer dataNodeContainer,
-            final String realName) {
-        final Map<URI, DataSchemaNode> namespaceToDataSchemaNode = new HashMap<URI, DataSchemaNode>();
-        for (DataSchemaNode dataSchemaNode : dataNodeContainer.getChildNodes()) {
-            if (dataSchemaNode.equals(realName)) {
-                namespaceToDataSchemaNode.put(dataSchemaNode.getQName().getNamespace(), dataSchemaNode);
-            }
-        }
-        return namespaceToDataSchemaNode;
-    }
-
-    private final Stack<DataSchemaNode> checkElementAndSchemaNodeNameAndNamespace(final StartElement startElement,
-            final DataSchemaNode node) {
-        checkArgument(startElement != null, "Start Element cannot be NULL!");
-        final String expectedName = node.getQName().getLocalName();
-        final String xmlName = getLocalNameFor(startElement);
-        final URI expectedNamespace = node.getQName().getNamespace();
-        final URI xmlNamespace = getNamespaceFor(startElement);
-        if (!expectedName.equals(xmlName)) {
-            throw new RestconfDocumentedException("Xml element name: " + xmlName + "\nSchema node name: "
-                    + expectedName, org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType.APPLICATION,
-                    ErrorTag.INVALID_VALUE);
-        }
-
-        if (xmlNamespace != null && !expectedNamespace.equals(xmlNamespace)) {
-            throw new RestconfDocumentedException("Xml element ns: " + xmlNamespace + "\nSchema node ns: "
-                    + expectedNamespace,
-                    org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType.APPLICATION,
-                    ErrorTag.INVALID_VALUE);
-        }
-        Stack<DataSchemaNode> processingQueueSchema = new Stack<>();
-        processingQueueSchema.push(node);
-        return processingQueueSchema;
-    }
-
-    /**
-     * If the input stream is not markable, then it wraps the input stream with a buffered stream, which is mark able.
-     * That way we can check if the stream is empty safely.
-     *
-     * @param entityStream
-     * @return
-     */
-    private InputStream getMarkableStream(InputStream entityStream) {
-        if (!entityStream.markSupported()) {
-            entityStream = new BufferedInputStream(entityStream);
-        }
-        return entityStream;
-    }
-
-    private boolean isInputStreamEmpty(final InputStream entityStream) throws IOException {
-        boolean isEmpty = false;
-        entityStream.mark(1);
-        if (entityStream.read() == -1) {
-            isEmpty = true;
-        }
-        entityStream.reset();
-        return isEmpty;
-    }
-
-    private boolean isSimpleNodeEvent(final XMLEvent event) throws XMLStreamException {
-        checkArgument(event != null, "XML Event cannot be NULL!");
-        if (event.isStartElement()) {
-            XMLEvent innerEvent = skipCommentsAndWhitespace();
-            if (innerEvent != null && (innerEvent.isCharacters() || innerEvent.isEndElement())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isCompositeNodeEvent(final XMLEvent event) throws XMLStreamException {
-        checkArgument(event != null, "XML Event cannot be NULL!");
-        if (event.isStartElement()) {
-            XMLEvent innerEvent = skipCommentsAndWhitespace();
-            if (innerEvent != null) {
-                if (innerEvent.isStartElement()) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private XMLEvent skipCommentsAndWhitespace() throws XMLStreamException {
-        while (eventReader.hasNext()) {
-            XMLEvent event = eventReader.peek();
-            if (event.getEventType() == XMLStreamConstants.COMMENT) {
-                eventReader.nextEvent();
-                continue;
-            }
-
-            if (event.isCharacters()) {
-                Characters chars = event.asCharacters();
-                if (chars.isWhiteSpace()) {
-                    eventReader.nextEvent();
-                    continue;
-                }
-            }
-            return event;
-        }
-        return null;
-    }
-
-    private CompositeNodeWrapper resolveCompositeNodeFromStartElement(final QName qName) {
-        // checkArgument(startElement != null, "Start Element cannot be NULL!");
-        CompositeNodeWrapper compositeNodeWrapper = new CompositeNodeWrapper("dummy");
-        compositeNodeWrapper.setQname(qName);
-        return compositeNodeWrapper;
-
-    }
-
-    private SimpleNodeWrapper resolveSimpleNodeFromStartElement(final DataSchemaNode node, final String value)
-            throws XMLStreamException {
-        // checkArgument(startElement != null, "Start Element cannot be NULL!");
-        Object deserializedValue = null;
-
-        if (node instanceof LeafSchemaNode) {
-            TypeDefinition<?> baseType = RestUtil.resolveBaseTypeFrom(((LeafSchemaNode) node).getType());
-            deserializedValue = RestCodec.from(baseType, iiWithSchema.getMountPoint()).deserialize(value);
-        } else if (node instanceof LeafListSchemaNode) {
-            TypeDefinition<?> baseType = RestUtil.resolveBaseTypeFrom(((LeafListSchemaNode) node).getType());
-            deserializedValue = RestCodec.from(baseType, iiWithSchema.getMountPoint()).deserialize(value);
-        }
-        // String data;
-        // if (data == null) {
-        // return new EmptyNodeWrapper(getNamespaceFor(startElement), getLocalNameFor(startElement));
-        // }
-        SimpleNodeWrapper simpleNodeWrapper = new SimpleNodeWrapper("dummy", deserializedValue);
-        simpleNodeWrapper.setQname(node.getQName());
-        return simpleNodeWrapper;
-    }
-
-    private String getValueOf(final StartElement startElement) throws XMLStreamException {
-        String data = null;
-        if (eventReader.hasNext()) {
-            final XMLEvent innerEvent = eventReader.peek();
-            if (innerEvent.isCharacters()) {
-                final Characters chars = innerEvent.asCharacters();
-                if (!chars.isWhiteSpace()) {
-                    data = innerEvent.asCharacters().getData();
-                    data = data + getAdditionalData(eventReader.nextEvent());
-                }
-            } else if (innerEvent.isEndElement()) {
-                if (startElement.getLocation().getCharacterOffset() == innerEvent.getLocation().getCharacterOffset()) {
-                    data = null;
-                } else {
-                    data = "";
-                }
-            }
-        }
-        return data == null ? null : data.trim();
-    }
-
-    private String getAdditionalData(final XMLEvent event) throws XMLStreamException {
-        String data = "";
-        if (eventReader.hasNext()) {
-            final XMLEvent innerEvent = eventReader.peek();
-            if (innerEvent.isCharacters() && !innerEvent.isEndElement()) {
-                final Characters chars = innerEvent.asCharacters();
-                if (!chars.isWhiteSpace()) {
-                    data = innerEvent.asCharacters().getData();
-                    data = data + getAdditionalData(eventReader.nextEvent());
-                }
-            }
-        }
-        return data;
-    }
-
-    private String getLocalNameFor(final StartElement startElement) {
-        return startElement.getName().getLocalPart();
-    }
-
-    private URI getNamespaceFor(final StartElement startElement) {
-        String namespaceURI = startElement.getName().getNamespaceURI();
-        return namespaceURI.isEmpty() ? null : URI.create(namespaceURI);
-    }
-
-    private Object resolveValueOfElement(final String value, final StartElement startElement) {
-        // it could be instance-identifier Built-In Type
-        if (value.startsWith("/")) {
-            IdentityValuesDTO iiValue = RestUtil.asInstanceIdentifier(value, new RestUtil.PrefixMapingFromXml(
-                    startElement));
-            if (iiValue != null) {
-                return iiValue;
-            }
-        }
-        // it could be identityref Built-In Type
-        String[] namespaceAndValue = value.split(":");
-        if (namespaceAndValue.length == 2) {
-            String namespace = startElement.getNamespaceContext().getNamespaceURI(namespaceAndValue[0]);
-            if (namespace != null && !namespace.isEmpty()) {
-                return new IdentityValuesDTO(namespace, namespaceAndValue[1], namespaceAndValue[0], value);
-            }
-        }
-        // it is not "prefix:value" but just "value"
-        return value;
-    }
-
-}
index f11e25c046feab69fe3c41f229dfdbadd496e18d..8dbc5b50ee5dbd8ac374ef7d1452384442923085 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.restconf.impl;
 
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.ListenableFuture;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
@@ -40,6 +41,7 @@ import javax.ws.rs.core.Response.Status;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
@@ -176,31 +178,39 @@ public class BrokerFacade {
     private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
             LogicalDatastoreType datastore, YangInstanceIdentifier path) {
         LOG.trace("Read " + datastore.name() + " via Restconf: {}", path);
-        final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture =
-                                                                 transaction.read(datastore, path);
+        final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
+        if (listenableFuture != null) {
+            Optional<NormalizedNode<?, ?>> optional;
+            try {
+                LOG.debug("Reading result data from transaction.");
+                optional = listenableFuture.get();
+            } catch (InterruptedException | ExecutionException e) {
+                throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause());
 
-        try {
-            Optional<NormalizedNode<?, ?>> optional = listenableFuture.checkedGet();
-            return optional.isPresent() ? optional.get() : null;
-        } catch(ReadFailedException e) {
-            throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
+            }
+            if (optional != null) {
+                if (optional.isPresent()) {
+                    return optional.get();
+                }
+            }
         }
+        return null;
     }
 
     private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
             final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
             final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, DataNormalizationOperation<?> root) {
-        CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> futureDatastoreData =
-                                                               rWTransaction.read(datastore, path);
+        ListenableFuture<Optional<NormalizedNode<?, ?>>> futureDatastoreData = rWTransaction.read(datastore, path);
         try {
-            final Optional<NormalizedNode<?, ?>> optionalDatastoreData = futureDatastoreData.checkedGet();
+            final Optional<NormalizedNode<?, ?>> optionalDatastoreData = futureDatastoreData.get();
             if (optionalDatastoreData.isPresent() && payload.equals(optionalDatastoreData.get())) {
-                LOG.trace("Post Configuration via Restconf was not executed because data already exists :{}", path);
+                String errMsg = "Post Configuration via Restconf was not executed because data already exists";
+                LOG.trace(errMsg + ":{}", path);
                 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
                         ErrorTag.DATA_EXISTS);
             }
-        } catch(ReadFailedException e) {
-            LOG.warn("Error reading from datastore with path: " + path, e);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.trace("It wasn't possible to get data loaded from datastore at path " + path);
         }
 
         ensureParentsByMerge(datastore, path, rWTransaction, root);
@@ -241,21 +251,27 @@ public class BrokerFacade {
             try {
                 currentOp = currentOp.getChild(currentArg);
             } catch (DataNormalizationException e) {
-                throw new RestconfDocumentedException(
-                        String.format("Error normalizing data for path %s", normalizedPath), e);
+                throw new IllegalArgumentException(
+                        String.format("Invalid child encountered in path %s", normalizedPath), e);
             }
             currentArguments.add(currentArg);
             YangInstanceIdentifier currentPath = YangInstanceIdentifier.create(currentArguments);
 
+            final Boolean exists;
+
             try {
 
-                boolean exists = rwTx.exists(store, currentPath).checkedGet();
-                if (!exists && iterator.hasNext()) {
-                    rwTx.merge(store, currentPath, currentOp.createDefault(currentArg));
-                }
+                CheckedFuture<Boolean, ReadFailedException> future =
+                    rwTx.exists(store, currentPath);
+                exists = future.checkedGet();
             } catch (ReadFailedException e) {
                 LOG.error("Failed to read pre-existing data from store {} path {}", store, currentPath, e);
-                throw new RestconfDocumentedException("Failed to read pre-existing data", e);
+                throw new IllegalStateException("Failed to read pre-existing data", e);
+            }
+
+
+            if (!exists && iterator.hasNext()) {
+                rwTx.merge(store, currentPath, currentOp.createDefault(currentArg));
             }
         }
     }
index 93e6a2c0e98504e169703423837177078992c2a4..b0a6e0d6f3885f20242d483044c0cfa92af1dea6 100644 (file)
@@ -118,15 +118,19 @@ public class ControllerContext implements SchemaContextListener {
         this.onGlobalContextUpdated(schemas);
     }
 
-    public InstanceIdWithSchemaNode toInstanceIdentifier(final String restconfInstance) {
+    public InstanceIdentifierContext toInstanceIdentifier(final String restconfInstance) {
         return this.toIdentifier(restconfInstance, false);
     }
 
-    public InstanceIdWithSchemaNode toMountPointIdentifier(final String restconfInstance) {
+    public SchemaContext getGlobalSchema() {
+        return globalSchema;
+    }
+
+    public InstanceIdentifierContext toMountPointIdentifier(final String restconfInstance) {
         return this.toIdentifier(restconfInstance, true);
     }
 
-    private InstanceIdWithSchemaNode toIdentifier(final String restconfInstance, final boolean toMountPointIdentifier) {
+    private InstanceIdentifierContext toIdentifier(final String restconfInstance, final boolean toMountPointIdentifier) {
         this.checkPreconditions();
 
         final List<String> pathArgs = urlPathArgsDecode(SLASH_SPLITTER.split(restconfInstance));
@@ -144,7 +148,7 @@ public class ControllerContext implements SchemaContextListener {
 
         InstanceIdentifierBuilder builder = YangInstanceIdentifier.builder();
         Module latestModule = globalSchema.findModuleByName(startModule, null);
-        InstanceIdWithSchemaNode iiWithSchemaNode = this.collectPathArguments(builder, pathArgs, latestModule, null,
+        InstanceIdentifierContext iiWithSchemaNode = this.collectPathArguments(builder, pathArgs, latestModule, null,
                 toMountPointIdentifier);
 
         if (iiWithSchemaNode == null) {
@@ -462,7 +466,7 @@ public class ControllerContext implements SchemaContextListener {
         return object == null ? "" : URLEncoder.encode(object.toString(), ControllerContext.URI_ENCODING_CHAR_SET);
     }
 
-    private InstanceIdWithSchemaNode collectPathArguments(final InstanceIdentifierBuilder builder,
+    private InstanceIdentifierContext collectPathArguments(final InstanceIdentifierBuilder builder,
             final List<String> strings, final DataNodeContainer parentNode, final DOMMountPoint mountPoint,
             final boolean returnJustMountPoint) {
         Preconditions.<List<String>> checkNotNull(strings);
@@ -472,7 +476,7 @@ public class ControllerContext implements SchemaContextListener {
         }
 
         if (strings.isEmpty()) {
-            return new InstanceIdWithSchemaNode(builder.toInstance(), ((DataSchemaNode) parentNode), mountPoint);
+            return new InstanceIdentifierContext(builder.toInstance(), ((DataSchemaNode) parentNode), mountPoint,mountPoint != null ? mountPoint.getSchemaContext() : globalSchema);
         }
 
         String head = strings.iterator().next();
@@ -511,12 +515,12 @@ public class ControllerContext implements SchemaContextListener {
 
                 if (returnJustMountPoint) {
                     YangInstanceIdentifier instance = YangInstanceIdentifier.builder().toInstance();
-                    return new InstanceIdWithSchemaNode(instance, mountPointSchema, mount);
+                    return new InstanceIdentifierContext(instance, mountPointSchema, mount,mountPointSchema);
                 }
 
                 if (strings.size() == 1) {
                     YangInstanceIdentifier instance = YangInstanceIdentifier.builder().toInstance();
-                    return new InstanceIdWithSchemaNode(instance, mountPointSchema, mount);
+                    return new InstanceIdentifierContext(instance, mountPointSchema, mount,mountPointSchema);
                 }
 
                 final String moduleNameBehindMountPoint = toModuleName(strings.get(1));
@@ -632,7 +636,7 @@ public class ControllerContext implements SchemaContextListener {
                     returnJustMountPoint);
         }
 
-        return new InstanceIdWithSchemaNode(builder.toInstance(), targetNode, mountPoint);
+        return new InstanceIdentifierContext(builder.toInstance(), targetNode, mountPoint,mountPoint != null ? mountPoint.getSchemaContext() : globalSchema);
     }
 
     public static DataSchemaNode findInstanceDataChildByNameAndNamespace(final DataNodeContainer container, final String name,
@@ -10,18 +10,21 @@ package org.opendaylight.controller.sal.restconf.impl;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-public class InstanceIdWithSchemaNode {
+public class InstanceIdentifierContext {
 
     private final YangInstanceIdentifier instanceIdentifier;
     private final DataSchemaNode schemaNode;
     private final DOMMountPoint mountPoint;
+    private final SchemaContext schemaContext;
 
-    public InstanceIdWithSchemaNode(YangInstanceIdentifier instanceIdentifier, DataSchemaNode schemaNode,
-            DOMMountPoint mountPoint) {
+    public InstanceIdentifierContext(YangInstanceIdentifier instanceIdentifier, DataSchemaNode schemaNode,
+            DOMMountPoint mountPoint,SchemaContext context) {
         this.instanceIdentifier = instanceIdentifier;
         this.schemaNode = schemaNode;
         this.mountPoint = mountPoint;
+        this.schemaContext = context;
     }
 
     public YangInstanceIdentifier getInstanceIdentifier() {
@@ -36,4 +39,8 @@ public class InstanceIdWithSchemaNode {
         return mountPoint;
     }
 
+    public SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
 }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NormalizedDataPrunner.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NormalizedDataPrunner.java
new file mode 100644 (file)
index 0000000..5d0185b
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl;
+
+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.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+
+class NormalizedDataPrunner {
+
+    public DataContainerChild<?, ?> pruneDataAtDepth(final DataContainerChild<?, ?> node, final Integer depth) {
+        if (depth == null) {
+            return node;
+        }
+
+        if (node instanceof LeafNode || node instanceof LeafSetNode || node instanceof AnyXmlNode
+                || node instanceof OrderedLeafSetNode) {
+            return node;
+        } else if (node instanceof MixinNode) {
+            return processMixinNode(node, depth);
+        } else if (node instanceof DataContainerNode) {
+            return processContainerNode(node, depth);
+        }
+        throw new IllegalStateException("Unexpected Mixin node occured why pruning data to requested depth");
+    }
+
+    private DataContainerChild<?, ?> processMixinNode(final NormalizedNode<?, ?> node, final Integer depth) {
+        if (node instanceof AugmentationNode) {
+            return processAugmentationNode(node, depth);
+        } else if (node instanceof ChoiceNode) {
+            return processChoiceNode(node, depth);
+        } else if (node instanceof OrderedMapNode) {
+            return processOrderedMapNode(node, depth);
+        } else if (node instanceof MapNode) {
+            return processMapNode(node, depth);
+        } else if (node instanceof UnkeyedListNode) {
+            return processUnkeyedListNode(node, depth);
+        }
+        throw new IllegalStateException("Unexpected Mixin node occured why pruning data to requested depth");
+    }
+
+    private DataContainerChild<?, ?> processContainerNode(final NormalizedNode<?, ?> node, final Integer depth) {
+        final ContainerNode containerNode = (ContainerNode) node;
+        DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> newContainerBuilder = Builders.containerBuilder()
+                .withNodeIdentifier(containerNode.getIdentifier());
+        if (depth > 1) {
+            processDataContainerChild((DataContainerNode<?>) node, depth, newContainerBuilder);
+        }
+        return newContainerBuilder.build();
+    }
+
+    private DataContainerChild<?, ?> processChoiceNode(final NormalizedNode<?, ?> node, final Integer depth) {
+        final ChoiceNode choiceNode = (ChoiceNode) node;
+        DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> newChoiceBuilder = Builders.choiceBuilder()
+                .withNodeIdentifier(choiceNode.getIdentifier());
+
+        processDataContainerChild((DataContainerNode<?>) node, depth, newChoiceBuilder);
+
+        return newChoiceBuilder.build();
+    }
+
+    private DataContainerChild<?, ?> processAugmentationNode(final NormalizedNode<?, ?> node, final Integer depth) {
+        final AugmentationNode augmentationNode = (AugmentationNode) node;
+        DataContainerNodeBuilder<AugmentationIdentifier, ? extends DataContainerChild<?, ?>> newAugmentationBuilder = Builders
+                .augmentationBuilder().withNodeIdentifier(augmentationNode.getIdentifier());
+
+        processDataContainerChild((DataContainerNode<?>) node, depth, newAugmentationBuilder);
+
+        return newAugmentationBuilder.build();
+    }
+
+    private void processDataContainerChild(
+            final DataContainerNode<?> node,
+            final Integer depth,
+            final DataContainerNodeBuilder<? extends YangInstanceIdentifier.PathArgument, ? extends DataContainerNode<?>> newBuilder) {
+
+        for (DataContainerChild<? extends PathArgument, ?> nodeValue : node.getValue()) {
+            newBuilder.withChild(pruneDataAtDepth(nodeValue, depth - 1));
+        }
+
+    }
+
+    private DataContainerChild<?, ?> processUnkeyedListNode(final NormalizedNode<?, ?> node, final Integer depth) {
+        CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> newUnkeyedListBuilder = Builders
+                .unkeyedListBuilder();
+        if (depth > 1) {
+            for (UnkeyedListEntryNode oldUnkeyedListEntry : ((UnkeyedListNode) node).getValue()) {
+                DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> newUnkeyedListEntry = Builders
+                        .unkeyedListEntryBuilder().withNodeIdentifier(oldUnkeyedListEntry.getIdentifier());
+                for (DataContainerChild<? extends PathArgument, ?> oldUnkeyedListEntryValue : oldUnkeyedListEntry
+                        .getValue()) {
+                    newUnkeyedListEntry.withChild(pruneDataAtDepth(oldUnkeyedListEntryValue, depth - 1));
+                }
+                newUnkeyedListBuilder.addChild(newUnkeyedListEntry.build());
+            }
+        }
+        return newUnkeyedListBuilder.build();
+    }
+
+    private DataContainerChild<?, ?> processOrderedMapNode(final NormalizedNode<?, ?> node, final Integer depth) {
+        CollectionNodeBuilder<MapEntryNode, OrderedMapNode> newOrderedMapNodeBuilder = Builders.orderedMapBuilder();
+        processMapEntries(node, depth, newOrderedMapNodeBuilder);
+        return newOrderedMapNodeBuilder.build();
+    }
+
+    private DataContainerChild<?, ?> processMapNode(final NormalizedNode<?, ?> node, final Integer depth) {
+        CollectionNodeBuilder<MapEntryNode, MapNode> newMapNodeBuilder = Builders.mapBuilder();
+        processMapEntries(node, depth, newMapNodeBuilder);
+        return newMapNodeBuilder.build();
+    }
+
+    private void processMapEntries(final NormalizedNode<?, ?> node, final Integer depth,
+            CollectionNodeBuilder<MapEntryNode, ? extends MapNode> newOrderedMapNodeBuilder) {
+        if (depth > 1) {
+            for (MapEntryNode oldMapEntryNode : ((MapNode) node).getValue()) {
+                DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> newMapEntryNodeBuilder = Builders
+                        .mapEntryBuilder().withNodeIdentifier(oldMapEntryNode.getIdentifier());
+                for (DataContainerChild<? extends PathArgument, ?> mapEntryNodeValue : oldMapEntryNode.getValue()) {
+                    newMapEntryNodeBuilder.withChild(pruneDataAtDepth(mapEntryNodeValue, depth - 1));
+                }
+                newOrderedMapNodeBuilder.withChild(newMapEntryNodeBuilder.build());
+            }
+        }
+    }
+
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NormalizedNodeContext.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NormalizedNodeContext.java
new file mode 100644 (file)
index 0000000..e698693
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.sal.restconf.impl;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class NormalizedNodeContext {
+
+    private final InstanceIdentifierContext context;
+    private final NormalizedNode<?,?> data;
+
+    public NormalizedNodeContext(InstanceIdentifierContext context, NormalizedNode<?, ?> data) {
+        this.context = context;
+        this.data = data;
+    }
+
+    public InstanceIdentifierContext getInstanceIdentifierContext() {
+        return context;
+    }
+
+    public NormalizedNode<?, ?> getData() {
+        return data;
+    }
+}
index b94f6a6166c47f3b1308f7dc4696341fe5ec202b..5d8c910afc31fa9d6420fc6d3a67466c34924317 100644 (file)
@@ -15,7 +15,7 @@ import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-
+import java.math.BigInteger;
 import java.net.URI;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -32,7 +32,6 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
-
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -87,6 +86,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class RestconfImpl implements RestconfService {
+
     private enum UriParameters {
         PRETTY_PRINT("prettyPrint"),
         DEPTH("depth");
@@ -103,6 +103,8 @@ public class RestconfImpl implements RestconfService {
         }
     }
 
+
+
     private final static RestconfImpl INSTANCE = new RestconfImpl();
 
     private static final int NOTIFICATION_PORT = 8181;
@@ -205,7 +207,7 @@ public class RestconfImpl implements RestconfService {
         Set<Module> modules = null;
         DOMMountPoint mountPoint = null;
         if (identifier.contains(ControllerContext.MOUNT)) {
-            InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier);
+            InstanceIdentifierContext mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier);
             mountPoint = mountPointIdentifier.getMountPoint();
             modules = this.controllerContext.getAllModules(mountPoint);
         } else {
@@ -236,7 +238,7 @@ public class RestconfImpl implements RestconfService {
         Module module = null;
         DOMMountPoint mountPoint = null;
         if (identifier.contains(ControllerContext.MOUNT)) {
-            InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier);
+            InstanceIdentifierContext mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier);
             mountPoint = mountPointIdentifier.getMountPoint();
             module = this.controllerContext.findModuleByNameAndRevision(mountPoint, moduleNameAndRevision);
         } else {
@@ -267,7 +269,7 @@ public class RestconfImpl implements RestconfService {
         Set<Module> modules = null;
         DOMMountPoint mountPoint = null;
         if (identifier.contains(ControllerContext.MOUNT)) {
-            InstanceIdWithSchemaNode mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier);
+            InstanceIdentifierContext mountPointIdentifier = this.controllerContext.toMountPointIdentifier(identifier);
             mountPoint = mountPointIdentifier.getMountPoint();
             modules = this.controllerContext.getAllModules(mountPoint);
         } else {
@@ -518,7 +520,7 @@ public class RestconfImpl implements RestconfService {
         DOMMountPoint mountPoint = null;
         if (identifier.contains(ControllerContext.MOUNT)) {
             // mounted RPC call - look up mount instance.
-            InstanceIdWithSchemaNode mountPointId = controllerContext.toMountPointIdentifier(identifier);
+            InstanceIdentifierContext mountPointId = controllerContext.toMountPointIdentifier(identifier);
             mountPoint = mountPointId.getMountPoint();
 
             int startOfRemoteRpcName = identifier.lastIndexOf(ControllerContext.MOUNT)
@@ -615,8 +617,8 @@ public class RestconfImpl implements RestconfService {
     }
 
     @Override
-    public StructuredData readConfigurationData(final String identifier, final UriInfo uriInfo) {
-        final InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier(identifier);
+    public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) {
+        final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
         DOMMountPoint mountPoint = iiWithData.getMountPoint();
         NormalizedNode<?, ?> data = null;
         YangInstanceIdentifier normalizedII;
@@ -628,12 +630,7 @@ public class RestconfImpl implements RestconfService {
             normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
             data = broker.readConfigurationData(normalizedII);
         }
-
-        final CompositeNode compositeNode = datastoreNormalizedNodeToCompositeNode(data, iiWithData.getSchemaNode());
-        final CompositeNode prunedCompositeNode = pruneDataAtDepth(compositeNode, parseDepthParameter(uriInfo));
-
-        final boolean prettyPrintMode = parsePrettyPrintParameter(uriInfo);
-        return new StructuredData(prunedCompositeNode, iiWithData.getSchemaNode(), mountPoint, prettyPrintMode);
+        return new NormalizedNodeContext(iiWithData, data);
     }
 
     @SuppressWarnings("unchecked")
@@ -679,8 +676,8 @@ public class RestconfImpl implements RestconfService {
     }
 
     @Override
-    public StructuredData readOperationalData(final String identifier, final UriInfo info) {
-        final InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier(identifier);
+    public NormalizedNodeContext readOperationalData(final String identifier, final UriInfo info) {
+        final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
         DOMMountPoint mountPoint = iiWithData.getMountPoint();
         NormalizedNode<?, ?> data = null;
         YangInstanceIdentifier normalizedII;
@@ -693,11 +690,7 @@ public class RestconfImpl implements RestconfService {
             data = broker.readOperationalData(normalizedII);
         }
 
-        final CompositeNode compositeNode = datastoreNormalizedNodeToCompositeNode(data, iiWithData.getSchemaNode());
-        final CompositeNode prunedCompositeNode = pruneDataAtDepth(compositeNode, parseDepthParameter(info));
-
-        final boolean prettyPrintMode = parsePrettyPrintParameter(info);
-        return new StructuredData(prunedCompositeNode, iiWithData.getSchemaNode(), mountPoint, prettyPrintMode);
+        return new NormalizedNodeContext(iiWithData, data);
     }
 
     private boolean parsePrettyPrintParameter(final UriInfo info) {
@@ -707,7 +700,7 @@ public class RestconfImpl implements RestconfService {
 
     @Override
     public Response updateConfigurationData(final String identifier, final Node<?> payload) {
-        final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
+        final InstanceIdentifierContext iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
 
         validateInput(iiWithData.getSchemaNode(), payload);
 
@@ -774,7 +767,7 @@ public class RestconfImpl implements RestconfService {
      *             if key values or key count in payload and URI isn't equal
      *
      */
-    private void validateListKeysEqualityInPayloadAndUri(final InstanceIdWithSchemaNode iiWithData,
+    private void validateListKeysEqualityInPayloadAndUri(final InstanceIdentifierContext iiWithData,
             final CompositeNode payload) {
         if (iiWithData.getSchemaNode() instanceof ListSchemaNode) {
             final List<QName> keyDefinitions = ((ListSchemaNode) iiWithData.getSchemaNode()).getKeyDefinition();
@@ -825,7 +818,7 @@ public class RestconfImpl implements RestconfService {
                     ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE);
         }
 
-        InstanceIdWithSchemaNode iiWithData = null;
+        InstanceIdentifierContext iiWithData = null;
         CompositeNode value = null;
         if (this.representsMountPointRootData(payload)) {
             // payload represents mount point data and URI represents path to the mount point
@@ -841,7 +834,7 @@ public class RestconfImpl implements RestconfService {
 
             value = this.normalizeNode(payload, iiWithData.getSchemaNode(), iiWithData.getMountPoint());
         } else {
-            final InstanceIdWithSchemaNode incompleteInstIdWithData = this.controllerContext
+            final InstanceIdentifierContext incompleteInstIdWithData = this.controllerContext
                     .toInstanceIdentifier(identifier);
             final DataNodeContainer parentSchema = (DataNodeContainer) incompleteInstIdWithData.getSchemaNode();
             DOMMountPoint mountPoint = incompleteInstIdWithData.getMountPoint();
@@ -856,7 +849,7 @@ public class RestconfImpl implements RestconfService {
                     parentSchema, payloadName, module.getNamespace());
             value = this.normalizeNode(payload, schemaNode, mountPoint);
 
-            iiWithData = addLastIdentifierFromData(incompleteInstIdWithData, value, schemaNode);
+            iiWithData = addLastIdentifierFromData(incompleteInstIdWithData, value, schemaNode,incompleteInstIdWithData.getSchemaContext());
         }
 
         final NormalizedNode<?, ?> datastoreNormalizedData = compositeNodeToDatastoreNormalizedNode(value,
@@ -906,7 +899,7 @@ public class RestconfImpl implements RestconfService {
         final DataSchemaNode schemaNode = ControllerContext.findInstanceDataChildByNameAndNamespace(module,
                 payloadName, module.getNamespace());
         final CompositeNode value = this.normalizeNode(payload, schemaNode, null);
-        final InstanceIdWithSchemaNode iiWithData = this.addLastIdentifierFromData(null, value, schemaNode);
+        final InstanceIdentifierContext iiWithData = this.addLastIdentifierFromData(null, value, schemaNode,ControllerContext.getInstance().getGlobalSchema());
         final NormalizedNode<?, ?> datastoreNormalizedData = compositeNodeToDatastoreNormalizedNode(value, schemaNode);
         DOMMountPoint mountPoint = iiWithData.getMountPoint();
         YangInstanceIdentifier normalizedII;
@@ -932,7 +925,7 @@ public class RestconfImpl implements RestconfService {
 
     @Override
     public Response deleteConfigurationData(final String identifier) {
-        final InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier(identifier);
+        final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
         DOMMountPoint mountPoint = iiWithData.getMountPoint();
         YangInstanceIdentifier normalizedII;
 
@@ -1098,8 +1091,8 @@ public class RestconfImpl implements RestconfService {
         return module;
     }
 
-    private InstanceIdWithSchemaNode addLastIdentifierFromData(final InstanceIdWithSchemaNode identifierWithSchemaNode,
-            final CompositeNode data, final DataSchemaNode schemaOfData) {
+    private InstanceIdentifierContext addLastIdentifierFromData(final InstanceIdentifierContext identifierWithSchemaNode,
+            final CompositeNode data, final DataSchemaNode schemaOfData, SchemaContext schemaContext) {
         YangInstanceIdentifier instanceIdentifier = null;
         if (identifierWithSchemaNode != null) {
             instanceIdentifier = identifierWithSchemaNode.getInstanceIdentifier();
@@ -1122,11 +1115,12 @@ public class RestconfImpl implements RestconfService {
 
         YangInstanceIdentifier instance = iiBuilder.toInstance();
         DOMMountPoint mountPoint = null;
+        SchemaContext schemaCtx = null;
         if (identifierWithSchemaNode != null) {
             mountPoint = identifierWithSchemaNode.getMountPoint();
         }
 
-        return new InstanceIdWithSchemaNode(instance, schemaOfData, mountPoint);
+        return new InstanceIdentifierContext(instance, schemaOfData, mountPoint,schemaContext);
     }
 
     private HashMap<QName, Object> resolveKeysFromData(final ListSchemaNode listNode, final CompositeNode dataNode) {
@@ -1514,16 +1508,16 @@ public class RestconfImpl implements RestconfService {
                 "It wasn't possible to translate specified data to datastore readable form."));
     }
 
-    private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode(
-            final InstanceIdWithSchemaNode iiWithSchemaNode) {
+    private InstanceIdentifierContext normalizeInstanceIdentifierWithSchemaNode(
+            final InstanceIdentifierContext iiWithSchemaNode) {
         return normalizeInstanceIdentifierWithSchemaNode(iiWithSchemaNode, false);
     }
 
-    private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode(
-            final InstanceIdWithSchemaNode iiWithSchemaNode, final boolean unwrapLastListNode) {
-        return new InstanceIdWithSchemaNode(instanceIdentifierToReadableFormForNormalizeNode(
+    private InstanceIdentifierContext normalizeInstanceIdentifierWithSchemaNode(
+            final InstanceIdentifierContext iiWithSchemaNode, final boolean unwrapLastListNode) {
+        return new InstanceIdentifierContext(instanceIdentifierToReadableFormForNormalizeNode(
                 iiWithSchemaNode.getInstanceIdentifier(), unwrapLastListNode), iiWithSchemaNode.getSchemaNode(),
-                iiWithSchemaNode.getMountPoint());
+                iiWithSchemaNode.getMountPoint(),iiWithSchemaNode.getSchemaContext());
     }
 
     private YangInstanceIdentifier instanceIdentifierToReadableFormForNormalizeNode(
@@ -1560,4 +1554,9 @@ public class RestconfImpl implements RestconfService {
         }
         return false;
     }
+
+    public BigInteger getOperationalReceived() {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
@@ -5,35 +5,41 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.sal.rest.impl;
+package org.opendaylight.controller.sal.restconf.impl;
 
-import java.util.Collection;
-import java.util.Collections;
+import org.opendaylight.controller.config.yang.md.sal.rest.connector.Config;
+import org.opendaylight.controller.config.yang.md.sal.rest.connector.Get;
+import org.opendaylight.controller.config.yang.md.sal.rest.connector.Operational;
+import org.opendaylight.controller.config.yang.md.sal.rest.connector.Post;
+import org.opendaylight.controller.config.yang.md.sal.rest.connector.Put;
+import org.opendaylight.controller.config.yang.md.sal.rest.connector.RestConnectorRuntimeMXBean;
+import org.opendaylight.controller.config.yang.md.sal.rest.connector.Rpcs;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.rest.api.RestConnector;
-import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
-import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.controller.sal.streams.websockets.WebSocketServer;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 
-public class RestconfProviderImpl implements Provider, AutoCloseable, RestConnector {
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Collections;
 
-    public final static String NOT_INITALIZED_MSG = "Restconf is not initialized yet. Please try again later";
+public class RestconfProviderImpl implements Provider, AutoCloseable, RestConnector, RestConnectorRuntimeMXBean {
 
+    private final StatisticsRestconfServiceWrapper stats = StatisticsRestconfServiceWrapper.getInstance();
     private ListenerRegistration<SchemaContextListener> listenerRegistration;
     private PortNumber port;
+    private Thread webSocketServerThread;
+
     public void setWebsocketPort(PortNumber port) {
         this.port = port;
     }
 
-    private Thread webSocketServerThread;
-
     @Override
     public void onSessionInitiated(ProviderSession session) {
         final DOMDataBroker domDataBroker = session.getService(DOMDataBroker.class);
@@ -58,9 +64,45 @@ public class RestconfProviderImpl implements Provider, AutoCloseable, RestConnec
 
     @Override
     public void close() {
+
         if (listenerRegistration != null) {
             listenerRegistration.close();
         }
+
+        WebSocketServer.destroyInstance();
         webSocketServerThread.interrupt();
     }
+
+    @Override
+    public Config getConfig() {
+        Config config = new Config();
+        Get get = new Get();
+        get.setReceivedRequests(stats.getConfigGet());
+        config.setGet(get);
+        Post post = new Post();
+        post.setReceivedRequests(stats.getConfigPost());
+        config.setPost(post);
+        Put put = new Put();
+        put.setReceivedRequests(stats.getConfigPut());
+        config.setPut(put);
+        return config;
+    }
+
+    @Override
+    public Operational getOperational() {
+        BigInteger opGet = stats.getOperationalGet();
+        Operational operational = new Operational();
+        Get get = new Get();
+        get.setReceivedRequests(opGet);
+        operational.setGet(get);
+        return operational;
+    }
+
+    @Override
+    public Rpcs getRpcs() {
+        BigInteger rpcInvoke = stats.getRpc();
+        Rpcs rpcs = new Rpcs();
+        rpcs.setReceivedRequests(rpcInvoke);
+        return rpcs ;
+    }
 }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StatisticsRestconfServiceWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StatisticsRestconfServiceWrapper.java
new file mode 100644 (file)
index 0000000..eafbb81
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl;
+
+import java.math.BigInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.controller.sal.rest.api.RestconfService;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+public class StatisticsRestconfServiceWrapper implements RestconfService {
+
+    AtomicLong operationalGet = new AtomicLong();
+    AtomicLong configGet = new AtomicLong();
+    AtomicLong rpc = new AtomicLong();
+    AtomicLong configPost = new AtomicLong();
+    AtomicLong configPut = new AtomicLong();
+    AtomicLong configDelete = new AtomicLong();
+
+    private static final StatisticsRestconfServiceWrapper INSTANCE = new StatisticsRestconfServiceWrapper(RestconfImpl.getInstance());
+
+    final RestconfService delegate;
+
+    private StatisticsRestconfServiceWrapper(RestconfService delegate) {
+        this.delegate = delegate;
+    }
+
+    public static StatisticsRestconfServiceWrapper getInstance() {
+        return INSTANCE;
+    }
+
+    @Override
+    public Object getRoot() {
+        return delegate.getRoot();
+    }
+
+    @Override
+    public StructuredData getModules(UriInfo uriInfo) {
+        return delegate.getModules(uriInfo);
+    }
+
+    @Override
+    public StructuredData getModules(String identifier, UriInfo uriInfo) {
+        return delegate.getModules(identifier, uriInfo);
+    }
+
+    @Override
+    public StructuredData getModule(String identifier, UriInfo uriInfo) {
+        return delegate.getModule(identifier, uriInfo);
+    }
+
+    @Override
+    public StructuredData getOperations(UriInfo uriInfo) {
+        return delegate.getOperations(uriInfo);
+    }
+
+    @Override
+    public StructuredData getOperations(String identifier, UriInfo uriInfo) {
+        return delegate.getOperations(identifier, uriInfo);
+    }
+
+    @Override
+    public StructuredData invokeRpc(String identifier, CompositeNode payload, UriInfo uriInfo) {
+        rpc.incrementAndGet();
+        return delegate.invokeRpc(identifier, payload, uriInfo);
+    }
+
+    @Override
+    public StructuredData invokeRpc(String identifier, String noPayload, UriInfo uriInfo) {
+        rpc.incrementAndGet();
+        return delegate.invokeRpc(identifier, noPayload, uriInfo);
+    }
+
+    @Override
+    public NormalizedNodeContext readConfigurationData(String identifier, UriInfo uriInfo) {
+        configGet.incrementAndGet();
+        return delegate.readConfigurationData(identifier, uriInfo);
+    }
+
+    @Override
+    public NormalizedNodeContext readOperationalData(String identifier, UriInfo uriInfo) {
+        operationalGet.incrementAndGet();
+        return delegate.readOperationalData(identifier, uriInfo);
+    }
+
+    @Override
+    public Response updateConfigurationData(String identifier, Node<?> payload) {
+        configPut.incrementAndGet();
+        return delegate.updateConfigurationData(identifier, payload);
+    }
+
+    @Override
+    public Response createConfigurationData(String identifier, Node<?> payload) {
+        configPost.incrementAndGet();
+        return delegate.createConfigurationData(identifier, payload);
+    }
+
+    @Override
+    public Response createConfigurationData(Node<?> payload) {
+        configPost.incrementAndGet();
+        return delegate.createConfigurationData(payload);
+    }
+
+    @Override
+    public Response deleteConfigurationData(String identifier) {
+        return delegate.deleteConfigurationData(identifier);
+    }
+
+    @Override
+    public Response subscribeToStream(String identifier, UriInfo uriInfo) {
+        return delegate.subscribeToStream(identifier, uriInfo);
+    }
+
+    @Override
+    public StructuredData getAvailableStreams(UriInfo uriInfo) {
+        return delegate.getAvailableStreams(uriInfo);
+    }
+
+    public BigInteger getConfigDelete() {
+        return BigInteger.valueOf(configDelete.get());
+    }
+
+    public BigInteger getConfigGet() {
+        return BigInteger.valueOf(configGet.get());
+    }
+
+    public BigInteger getConfigPost() {
+        return BigInteger.valueOf(configPost.get());
+    }
+
+    public BigInteger getConfigPut() {
+        return BigInteger.valueOf(configPut.get());
+    }
+
+    public BigInteger getOperationalGet() {
+        return BigInteger.valueOf(operationalGet.get());
+    }
+
+    public BigInteger getRpc() {
+        return BigInteger.valueOf(rpc.get());
+    }
+
+}
index 67ed44f84ea86020b54553f3f0b4f108e4ada66f..0a5f5f0ff03be26086ede6a78d3ba2dd156e812c 100644 (file)
@@ -16,11 +16,10 @@ import org.slf4j.LoggerFactory;
 public class WebSocketServer implements Runnable {
 
     private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
-    public static final String WEBSOCKET_SERVER_CONFIG_PROPERTY = "restconf.websocket.port";
     public static final int DEFAULT_PORT = 8181;
     private EventLoopGroup bossGroup;
     private EventLoopGroup workerGroup;
-    private static WebSocketServer singleton = null;
+    private static WebSocketServer instance = null;
     private int port = DEFAULT_PORT;
 
     private WebSocketServer(int port) {
@@ -35,14 +34,11 @@ public class WebSocketServer implements Runnable {
      * @return instance of {@link WebSocketServer}
      */
     public static WebSocketServer createInstance(int port) {
-        if (singleton != null) {
-            throw new IllegalStateException("createInstance() has already been called");
-        }
-        if (port < 1024) {
-            throw new IllegalArgumentException("Privileged port (below 1024) is not allowed");
-        }
-        singleton = new WebSocketServer(port);
-        return singleton;
+        Preconditions.checkState(instance == null, "createInstance() has already been called");
+        Preconditions.checkArgument(port > 1024, "Privileged port (below 1024) is not allowed");
+
+        instance = new WebSocketServer(port);
+        return instance;
     }
 
     /**
@@ -58,18 +54,18 @@ public class WebSocketServer implements Runnable {
      * @return instance of {@link WebSocketServer}
      */
     public static WebSocketServer getInstance() {
-        Preconditions.checkNotNull(singleton, "createInstance() must be called prior to getInstance()");
-        return singleton;
+        Preconditions.checkNotNull(instance, "createInstance() must be called prior to getInstance()");
+        return instance;
     }
 
     /**
      * Destroy this already created instance
      */
     public static void destroyInstance() {
-        if (singleton == null) {
-            throw new IllegalStateException("createInstance() must be called prior to destroyInstance()");
-        }
-        getInstance().stop();
+        Preconditions.checkState(instance != null, "createInstance() must be called prior to destroyInstance()");
+
+        instance.stop();
+        instance = null;
     }
 
     @Override
@@ -99,9 +95,11 @@ public class WebSocketServer implements Runnable {
         Notificator.removeAllListeners();
         if (bossGroup != null) {
             bossGroup.shutdownGracefully();
+            bossGroup = null;
         }
         if (workerGroup != null) {
             workerGroup.shutdownGracefully();
+            workerGroup = null;
         }
     }
 
index a8fc8ff4d54b6e149e562570b38a69ab01afcfba..6d2add6ff14313b8824a5ade4d8cba187260bc24 100644 (file)
@@ -27,6 +27,12 @@ module opendaylight-rest-connector {
         config:java-name-prefix RestConnector;
     }
     
+    grouping statistics {
+        leaf received-requests {
+           type uint64;
+        }
+    }
+
     augment "/config:modules/config:module/config:configuration" {
         case rest-connector-impl {
             when "/config:modules/config:module/config:type = 'rest-connector-impl'";
@@ -44,4 +50,33 @@ module opendaylight-rest-connector {
             }
         }
     }
+    
+    augment "/config:modules/config:module/config:state" {
+        case rest-connector-impl {
+            when "/config:modules/config:module/config:type = 'rest-connector-impl'";
+            container rpcs {
+                uses statistics;
+            }
+
+            container config {
+                container get {
+                    uses statistics;
+                }
+                
+                container post {
+                    uses statistics;
+                }
+                
+                container put {
+                    uses statistics;
+                }
+            }
+
+            container operational {
+                container get {
+                    uses statistics;
+                }
+            }
+        }
+    }
 }
\ No newline at end of file
index 2f045ce381ca0572cbeff4ad43147834fb59d2cf..559a6b9e8e4a8a88aed3f4c4c3b9a34d5ea377ae 100644 (file)
@@ -40,7 +40,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
-import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
@@ -324,7 +324,7 @@ public class InvokeRpcMethodTest {
         when(mockMountPoint.getService(eq(RpcProvisionRegistry.class))).thenReturn(Optional.of(mockedRpcProvisionRegistry));
         when(mockMountPoint.getSchemaContext()).thenReturn(TestUtils.loadSchemaContext("/invoke-rpc"));
 
-        InstanceIdWithSchemaNode mockedInstanceId = mock(InstanceIdWithSchemaNode.class);
+        InstanceIdentifierContext mockedInstanceId = mock(InstanceIdentifierContext.class);
         when(mockedInstanceId.getMountPoint()).thenReturn(mockMountPoint);
 
         ControllerContext mockedContext = mock(ControllerContext.class);
index bab06e92451985b5a0d95032e99174adb91ba4b0..856d8c006b6c40349d2a1fd646cc70db6bd5fd62 100644 (file)
@@ -17,7 +17,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
-import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
@@ -36,7 +36,7 @@ public class RestGetAugmentedElementWhenEqualNamesTest {
 
     @Test
     public void augmentedNodesInUri() {
-        InstanceIdWithSchemaNode iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-a:cont1");
+        InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-a:cont1");
         assertEquals("ns:augment:main:a", iiWithData.getSchemaNode().getQName().getNamespace().toString());
         iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-b:cont1");
         assertEquals("ns:augment:main:b", iiWithData.getSchemaNode().getQName().getNamespace().toString());
index 539248a147cd4eea16dca9f4725cf26e9b185496..06cfd84b05048513249462de9245871da3905c5f 100644 (file)
@@ -44,12 +44,14 @@ import javax.ws.rs.core.UriInfo;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.RestconfApplication;
 import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
@@ -130,6 +132,7 @@ public class RestGetOperationTest extends JerseyTest {
                 StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
                 JsonToCompositeNodeProvider.INSTANCE);
         resourceConfig.registerClasses(RestconfDocumentedExceptionMapper.class);
+        resourceConfig.registerClasses(new RestconfApplication().getClasses());
         return resourceConfig;
     }
 
@@ -717,6 +720,7 @@ public class RestGetOperationTest extends JerseyTest {
     }
 
     @Test
+    @Ignore
     public void getDataWithUriDepthParameterTest() throws UnsupportedEncodingException {
 
         ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
@@ -903,6 +907,7 @@ public class RestGetOperationTest extends JerseyTest {
      * Tests behavior when invalid value of depth URI parameter
      */
     @Test
+    @Ignore
     public void getDataWithInvalidDepthParameterTest() {
 
         ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
@@ -930,7 +935,7 @@ public class RestGetOperationTest extends JerseyTest {
         try {
             QName qNameDepth1Cont = QName.create("urn:nested:module", "2014-06-3", "depth1-cont");
             YangInstanceIdentifier ii = YangInstanceIdentifier.builder().node(qNameDepth1Cont).build();
-            NormalizedNode value = (NormalizedNode<?,?>)(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(qNameDepth1Cont)).build());
+            NormalizedNode value = (Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(qNameDepth1Cont)).build());
             when(brokerFacade.readConfigurationData(eq(ii))).thenReturn(value);
             restconfImpl.readConfigurationData("nested-module:depth1-cont", uriInfo);
             fail("Expected RestconfDocumentedException");
index 4e9c96ac3e8acef126077d7b932e737caae1e4f3..3a16b18efcf26e8704a06900fb16a36d32cb5a00 100644 (file)
@@ -53,6 +53,7 @@ import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.api.Draft02;
 import org.opendaylight.controller.sal.rest.api.RestconfService;
@@ -60,11 +61,11 @@ import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapp
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
 import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
 import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType;
-import org.opendaylight.controller.sal.restconf.impl.StructuredData;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -679,13 +680,14 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest {
     }
 
     @Test
+    @Ignore
     public void testToResponseWithStatusOnly() throws Exception {
 
         // The StructuredDataToJsonProvider should throw a
         // RestconfDocumentedException with no data
 
         when(mockRestConf.readOperationalData(any(String.class), any(UriInfo.class))).thenReturn(
-                new StructuredData(null, null, null));
+                new NormalizedNodeContext(null, null));
 
         Response resp = target("/operational/foo").request(MediaType.APPLICATION_JSON).get();
 
index c2b153f02bd27b6729dbba2a89a201a306763a99..15d73e3e7a301ca5a70879a851941eab0e4b35b3 100644 (file)
@@ -402,7 +402,7 @@ public final class TestUtils {
         return interfaceBuilder.toInstance();
     }
 
-    static NormalizedNode prepareNormalizedNodeWithIetfInterfacesInterfacesData() throws ParseException {
+    static NormalizedNode<?,?> prepareNormalizedNodeWithIetfInterfacesInterfacesData() throws ParseException {
         String ietfInterfacesDate = "2013-07-04";
         String namespace = "urn:ietf:params:xml:ns:yang:ietf-interfaces";
         DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntryNode = ImmutableMapEntryNodeBuilder.create();
index ed871bb52727895c5cdf69dd80e0caa2433cacef..4900e6a66f1ab9d9d3324c85e6ca5c98f103e5ba 100644 (file)
@@ -26,7 +26,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
-import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
+import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -51,7 +51,7 @@ public class URITest {
 
     @Test
     public void testToInstanceIdentifierList() throws FileNotFoundException {
-        InstanceIdWithSchemaNode instanceIdentifier = controllerContext
+        InstanceIdentifierContext instanceIdentifier = controllerContext
                 .toInstanceIdentifier("simple-nodes:userWithoutClass/foo");
         assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
 
@@ -80,7 +80,7 @@ public class URITest {
 
     @Test
     public void testToInstanceIdentifierContainer() throws FileNotFoundException {
-        InstanceIdWithSchemaNode instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:users");
+        InstanceIdentifierContext instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:users");
         assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "users");
         assertTrue(instanceIdentifier.getSchemaNode() instanceof ContainerSchemaNode);
         assertEquals(2, ((ContainerSchemaNode) instanceIdentifier.getSchemaNode()).getChildNodes().size());
@@ -88,7 +88,7 @@ public class URITest {
 
     @Test
     public void testToInstanceIdentifierChoice() throws FileNotFoundException {
-        InstanceIdWithSchemaNode instanceIdentifier = controllerContext
+        InstanceIdentifierContext instanceIdentifier = controllerContext
                 .toInstanceIdentifier("simple-nodes:food/nonalcoholic");
         assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "nonalcoholic");
     }
@@ -120,7 +120,7 @@ public class URITest {
     @Test
     public void testMountPointWithExternModul() throws FileNotFoundException {
         initMountService(true);
-        InstanceIdWithSchemaNode instanceIdentifier = controllerContext
+        InstanceIdentifierContext instanceIdentifier = controllerContext
                 .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class/student/name");
         assertEquals(
                 "[(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)class, (urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)student[{(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)name=name}]]",
@@ -130,7 +130,7 @@ public class URITest {
     @Test
     public void testMountPointWithoutExternModul() throws FileNotFoundException {
         initMountService(true);
-        InstanceIdWithSchemaNode instanceIdentifier = controllerContext
+        InstanceIdentifierContext instanceIdentifier = controllerContext
                 .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/");
         assertTrue(Iterables.isEmpty(instanceIdentifier.getInstanceIdentifier().getPathArguments()));
     }
@@ -140,7 +140,7 @@ public class URITest {
         exception.expect(RestconfDocumentedException.class);
 
         controllerContext.setMountService(null);
-        InstanceIdWithSchemaNode instanceIdentifier = controllerContext
+        InstanceIdentifierContext instanceIdentifier = controllerContext
                 .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class/student/name");
     }
 
@@ -149,7 +149,7 @@ public class URITest {
         initMountService(false);
         exception.expect(RestconfDocumentedException.class);
 
-        InstanceIdWithSchemaNode instanceIdentifier = controllerContext
+        InstanceIdentifierContext instanceIdentifier = controllerContext
                 .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class");
     }
 
index 2a778180d4448dd33ce7cabb17f911e77151df9f..c470b3237ea7fe2dd69f37254cae4b38439c8861 100644 (file)
@@ -2,7 +2,9 @@
 <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     version="3.0">
-
+    <welcome-file-list>
+        <welcome-file>index.html</welcome-file>
+    </welcome-file-list>
     <servlet>
         <servlet-name>JAXRSApiDoc</servlet-name>
         <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
index 05a76a4cb7ca0551d0bb55322b4603f78eb7fd4b..f12616bc4b910d8127fc7269ea8bd5bc6b863dd5 100644 (file)
@@ -32,7 +32,7 @@
        var loadMount = function(mountIndex, mountPath) {\r
                $("#message").empty();\r
                $("#message").append( "<p>Loading...</p>" );\r
-               loadSwagger("http://localhost:8080/apidoc/apis/mounts/" + mountIndex,\r
+               loadSwagger("/apidoc/apis/mounts/" + mountIndex,\r
                                "swagger-ui-container");\r
                $("#message").empty();\r
                $("#message").append( "<h2><b>Showing mount points for " + mountPath + "</b></h2>");\r
@@ -48,7 +48,7 @@
        //loads the root swagger documenation (which comes from RestConf)\r
        var loadRootSwagger = function() {\r
                $("#message").empty();\r
-               loadSwagger("http://localhost:8080/apidoc/apis", "swagger-ui-container");\r
+               loadSwagger("/apidoc/apis", "swagger-ui-container");\r
        }\r
 \r
        //main method to initialize the mount list / swagger docs / tabs on page load\r
index e23ad0acdbe43a2603f458dd3a17b467116acd1b..838aeb7dc36af37ae0916fd1e60f708c8be1861d 100644 (file)
@@ -97,14 +97,15 @@ abstract class AbstractStatsTracker<I, K> {
     }
     protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item);
     protected abstract K updateSingleStat(DataModificationTransaction trans, I item);
+    protected abstract K createInvariantKey(K item);
     public abstract void request();
 
     public final synchronized void updateStats(List<I> list) {
 
         final DataModificationTransaction trans = startTransaction();
-
         for (final I item : list) {
-            trackedItems.put(updateSingleStat(trans, item), requestCounter);
+            K key = updateSingleStat(trans, item);
+            trackedItems.put(createInvariantKey(key), requestCounter);
         }
 
         trans.commit();
index b5b39d94d2f5839cf3901807f3435d93d53ba38d..c43c1ebaca211216a5046d65870b56b7ef432513 100644 (file)
@@ -56,4 +56,9 @@ final class FlowStatsEntry {
             return false;
         return true;
     }
+
+    @Override
+    public String toString() {
+        return "FlowStatsEntry [tableId=" + tableId + ", flow=" + flow + "]";
+    }
 }
index e92d0bd6251dbf89af9c98b175aa699d8d697994..d540f115c3ab7c107536a5797b3527e9dc7a36ba 100644 (file)
@@ -301,4 +301,13 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
         }
         return flowCookieMap;
     }
+
+    @Override
+    protected FlowStatsEntry createInvariantKey(final FlowStatsEntry item) {
+        FlowBuilder newFlow = new FlowBuilder();
+        newFlow.setId(item.getFlow().getId());
+        newFlow.setKey(item.getFlow().getKey());
+        newFlow.fieldsFrom(item.getFlow());
+        return new FlowStatsEntry(item.getTableId(),newFlow.build());
+    }
 }
index a160f6d467ca6731a8c4d485250d6697cec8b97e..2e850580416084c36a1de4c054d21a7860b8d394 100644 (file)
@@ -21,6 +21,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev13
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -70,4 +71,12 @@ final class FlowTableStatsTracker extends AbstractStatsTracker<FlowTableAndStati
             requestHelper(flowTableStatsService.getFlowTablesStatistics(input.build()));
         }
     }
+
+    @Override
+    protected FlowTableAndStatisticsMap createInvariantKey(FlowTableAndStatisticsMap item) {
+        FlowTableAndStatisticsMapBuilder flowTableAndStatisticsMapBuilder = new FlowTableAndStatisticsMapBuilder();
+        flowTableAndStatisticsMapBuilder.setTableId(item.getTableId());
+        flowTableAndStatisticsMapBuilder.setKey(item.getKey());
+        return flowTableAndStatisticsMapBuilder.build();
+    }
 }
index a775b73169dc5581cd3175eebfa078a471d5dbd3..11c6d4c22df5f53cd17d8bc089aa8b7338c8eceb 100644 (file)
@@ -114,4 +114,10 @@ final class GroupDescStatsTracker extends AbstractListeningStatsTracker<GroupDes
 
         super.start(dbs);
     }
+
+    @Override
+    protected GroupDescStats createInvariantKey(GroupDescStats item) {
+        // No invariant data exist in the group description stats.
+        return item;
+    }
 }
index c3c23c9b582cf493c02248087b08f80914b3fd82..f3ba45643c3fd4338b4f8f6bd8951de0d5184757 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStatsBuilder;
 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.GroupBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
@@ -105,4 +106,12 @@ final class GroupStatsTracker extends AbstractListeningStatsTracker<GroupStats,
 
         super.start(dbs);
     }
+
+    @Override
+    protected GroupStats createInvariantKey(GroupStats item) {
+        GroupStatsBuilder groupStatsBuilder = new GroupStatsBuilder();
+        groupStatsBuilder.setKey(item.getKey());
+        groupStatsBuilder.setGroupId(item.getGroupId());
+        return groupStatsBuilder.build();
+    }
 }
index ea412a09e183db8dcf958c6769a8b0ac37211c5f..88139fc60649541678f63edb46e8f9a250898644 100644 (file)
@@ -109,4 +109,10 @@ final class MeterConfigStatsTracker extends AbstractListeningStatsTracker<MeterC
 
         super.start(dbs);
     }
+
+    @Override
+    protected MeterConfigStats createInvariantKey(MeterConfigStats item) {
+        // No invariant data exist in the meter config stats.
+        return item;
+    }
 }
index be53a38f186eb2407b9ce30ff4a2e20da6379b53..f43ec693cd1d7a283a037f770361f1024ab4ed01 100644 (file)
@@ -20,6 +20,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -112,4 +113,12 @@ final class MeterStatsTracker extends AbstractListeningStatsTracker<MeterStats,
 
         super.start(dbs);
     }
+
+    @Override
+    protected MeterStats createInvariantKey(MeterStats item) {
+        MeterStatsBuilder meterStatsBuilder = new MeterStatsBuilder();
+        meterStatsBuilder.setKey(item.getKey());
+        meterStatsBuilder.setMeterId(item.getMeterId());
+        return meterStatsBuilder.build();
+    }
 }
index e4490eaa3cc2ea9ac2683ff36f6d48787ddded99..2e2bf1cd518b94a2b97c81b877b8372f447ef36e 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.G
 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -83,4 +84,12 @@ final class NodeConnectorStatsTracker extends AbstractStatsTracker<NodeConnector
             requestHelper(portStatsService.getAllNodeConnectorsStatistics(input.build()));
         }
     }
+
+    @Override
+    protected NodeConnectorStatisticsAndPortNumberMap createInvariantKey(NodeConnectorStatisticsAndPortNumberMap item) {
+        NodeConnectorStatisticsAndPortNumberMapBuilder ncStatsBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder();
+        ncStatsBuilder.setNodeConnectorId(item.getNodeConnectorId());
+        ncStatsBuilder.setKey(item.getKey());
+        return ncStatsBuilder.build();
+    }
 }
index 03f7808c8f9b119cfb6ed0ba2fe877d340e3ffc0..4a589703beb4303b9686d7887663b8f6d1492486 100644 (file)
@@ -152,4 +152,10 @@ final class QueueStatsTracker extends AbstractListeningStatsTracker<QueueIdAndSt
 
         super.start(dbs);
     }
+
+    @Override
+    protected QueueStatsEntry createInvariantKey(QueueStatsEntry item) {
+        // No invariant data exist in the group description stats.
+        return item;
+    }
 }
index 10aec4ca2e85038cdc7ff21dd0ebd4dc4b6cddf6..c1996f4691632637abc9fc7dffacce0bcb12f2ad 100644 (file)
@@ -151,7 +151,7 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open
             public void applyOperation(final ReadWriteTransaction transaction) {
                 final Link link = toTopologyLink(notification);
                 final InstanceIdentifier<Link> path = linkPath(link);
-                transaction.put(LogicalDatastoreType.OPERATIONAL, path, link);
+                transaction.merge(LogicalDatastoreType.OPERATIONAL, path, link, true);
             }
         });
     }
index d4073e5c178f1748ef71ee8466e70982646dab94..bd931c33d0212858b615aed61d843e1e6f1744d9 100644 (file)
  */
 package org.opendaylight.controller.netconf.it;
 
-import java.net.InetSocketAddress;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anySetOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.local.LocalAddress;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
 import org.junit.After;
 import org.junit.Before;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
+import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
+import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.w3c.dom.Element;
 
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.concurrent.GlobalEventExecutor;
+public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
 
-public class AbstractNetconfConfigTest extends AbstractConfigTest {
+    public static final String LOOPBACK_ADDRESS = "127.0.0.1";
+    public static final int SERVER_CONNECTION_TIMEOUT_MILLIS = 5000;
+
+    static ModuleFactory[] FACTORIES = { new TestImplModuleFactory(),
+            new DepTestImplModuleFactory(), new NetconfTestImplModuleFactory(),
+            new IdentityTestModuleFactory(), new MultipleDependenciesModuleFactory() };
 
     private EventLoopGroup nettyThreadgroup;
     private HashedWheelTimer hashedWheelTimer;
 
+    private NetconfClientDispatcherImpl clientDispatcher;
+    private Channel serverTcpChannel;
+
+    private NetconfMessage getConfig;
+    private NetconfMessage get;
+
+    /**
+     * @Before in subclasses is called after this method.
+     */
     @Before
-    public void setUpAbstractNetconfConfigTest() {
+    public void setUpAbstractNetconfConfigTest() throws Exception {
+        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, FACTORIES));
+
         nettyThreadgroup = new NioEventLoopGroup();
         hashedWheelTimer = new HashedWheelTimer();
+
+        loadMessages();
+
+        setUpTestInitial();
+
+        final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
+
+        for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getAdditionalServiceFactories()) {
+            factoriesListener.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
+        }
+
+        serverTcpChannel = startNetconfTcpServer(factoriesListener);
+        clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
+    }
+
+    /**
+     * Called before setUp method is executed, so test classes can set up resources before setUpAbstractNetconfConfigTest method is called.
+     */
+    protected void setUpTestInitial() throws Exception {}
+
+    private void loadMessages() throws Exception {
+        this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+        this.get = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/get.xml");
+    }
+
+    public NetconfMessage getGetConfig() {
+        return getConfig;
+    }
+
+    public NetconfMessage getGet() {
+        return get;
+    }
+
+    private Channel startNetconfTcpServer(final NetconfOperationServiceFactoryListenerImpl factoriesListener) throws Exception {
+        final NetconfServerDispatcher dispatch = createDispatcher(factoriesListener, getNetconfMonitoringService(), getNotificationProducer());
+
+        final ChannelFuture s;
+        if(getTcpServerAddress() instanceof LocalAddress) {
+            s = dispatch.createLocalServer(((LocalAddress) getTcpServerAddress()));
+        } else {
+            s = dispatch.createServer(((InetSocketAddress) getTcpServerAddress()));
+        }
+        s.await();
+        return s.channel();
+    }
+
+    protected DefaultCommitNotificationProducer getNotificationProducer() {
+        final DefaultCommitNotificationProducer notificationProducer = mock(DefaultCommitNotificationProducer.class);
+        doNothing().when(notificationProducer).close();
+        doNothing().when(notificationProducer).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
+        return notificationProducer;
+    }
+
+    protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories() {
+        return Collections.emptySet();
+    }
+
+    protected SessionMonitoringService getNetconfMonitoringService() throws Exception {
+        final NetconfOperationProvider netconfOperationProvider = mock(NetconfOperationProvider.class);
+        final NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
+        doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
+        doReturn(snap).when(netconfOperationProvider).openSnapshot(anyString());
+        return new NetconfMonitoringServiceImpl(netconfOperationProvider);
+    }
+
+    protected abstract SocketAddress getTcpServerAddress();
+
+    public NetconfClientDispatcherImpl getClientDispatcher() {
+        return clientDispatcher;
+    }
+
+    private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
+        final Collection<InputStream> yangDependencies = getBasicYangs();
+        return new HardcodedYangStoreService(yangDependencies);
+    }
+
+    static Collection<InputStream> getBasicYangs() throws IOException {
+
+        final List<String> paths = Arrays.asList(
+                "/META-INF/yang/config.yang",
+                "/META-INF/yang/rpc-context.yang",
+                "/META-INF/yang/config-test.yang",
+                "/META-INF/yang/config-test-impl.yang",
+                "/META-INF/yang/test-types.yang",
+                "/META-INF/yang/ietf-inet-types.yang");
+
+        final Collection<InputStream> yangDependencies = new ArrayList<>();
+        final List<String> failedToFind = new ArrayList<>();
+        for (final String path : paths) {
+            final InputStream resourceAsStream = NetconfITTest.class.getResourceAsStream(path);
+            if (resourceAsStream == null) {
+                failedToFind.add(path);
+            } else {
+                yangDependencies.add(resourceAsStream);
+            }
+        }
+        assertEquals("Some yang files were not found", Collections.<String>emptyList(), failedToFind);
+        return yangDependencies;
     }
 
     protected NetconfServerDispatcher createDispatcher(
-            NetconfOperationServiceFactoryListenerImpl factoriesListener, SessionMonitoringService sessionMonitoringService,
-            DefaultCommitNotificationProducer commitNotifier) {
-        SessionIdProvider idProvider = new SessionIdProvider();
+            final NetconfOperationServiceFactoryListenerImpl factoriesListener, final SessionMonitoringService sessionMonitoringService,
+            final DefaultCommitNotificationProducer commitNotifier) {
+        final SessionIdProvider idProvider = new SessionIdProvider();
 
-        NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                hashedWheelTimer, factoriesListener, idProvider, 5000, commitNotifier, sessionMonitoringService);
+        final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
+                hashedWheelTimer, factoriesListener, idProvider, SERVER_CONNECTION_TIMEOUT_MILLIS, commitNotifier, sessionMonitoringService);
 
-        NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
+        final NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
                 serverNegotiatorFactory);
         return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
     }
@@ -60,19 +222,58 @@ public class AbstractNetconfConfigTest extends AbstractConfigTest {
         return nettyThreadgroup;
     }
 
+    /**
+     * @After in subclasses is be called before this.
+     */
     @After
-    public void cleanUpTimer() {
+    public void cleanUpNetconf() throws Exception {
+        serverTcpChannel.close().await();
         hashedWheelTimer.stop();
-        nettyThreadgroup.shutdownGracefully();
+        nettyThreadgroup.shutdownGracefully().await();
     }
 
     public NetconfClientConfiguration getClientConfiguration(final InetSocketAddress tcpAddress, final int timeout) {
         final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
         b.withAddress(tcpAddress);
         b.withSessionListener(new SimpleNetconfClientSessionListener());
-        b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
-                timeout));
+        b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, timeout));
         b.withConnectionTimeoutMillis(timeout);
         return b.build();
     }
+
+    public static final class HardcodedYangStoreService implements YangStoreService {
+
+        private final List<InputStream> byteArrayInputStreams;
+
+        public HardcodedYangStoreService(final Collection<? extends InputStream> inputStreams) throws YangStoreException, IOException {
+            byteArrayInputStreams = new ArrayList<>();
+            for (final InputStream inputStream : inputStreams) {
+                assertNotNull(inputStream);
+                final byte[] content = IOUtils.toByteArray(inputStream);
+                final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content);
+                byteArrayInputStreams.add(byteArrayInputStream);
+            }
+        }
+
+        @Override
+        public YangStoreSnapshot getYangStoreSnapshot() throws YangStoreException {
+            for (final InputStream inputStream : byteArrayInputStreams) {
+                try {
+                    inputStream.reset();
+                } catch (final IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            final YangParserImpl yangParser = new YangParserImpl();
+            final SchemaContext schemaContext = yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(byteArrayInputStreams).values()));
+            final YangStoreServiceImpl yangStoreService = new YangStoreServiceImpl(new SchemaContextProvider() {
+                @Override
+                public SchemaContext getSchemaContext() {
+                    return schemaContext ;
+                }
+            });
+            return yangStoreService.getYangStoreSnapshot();
+        }
+    }
 }
diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/HardcodedYangStoreService.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/HardcodedYangStoreService.java
deleted file mode 100644 (file)
index 3fa1b01..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.it;
-
-import static org.junit.Assert.assertNotNull;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-
-import org.apache.commons.io.IOUtils;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreServiceImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-
-public class HardcodedYangStoreService implements YangStoreService {
-
-    private final List<InputStream> byteArrayInputStreams;
-
-    public HardcodedYangStoreService(
-            Collection<? extends InputStream> inputStreams)
-            throws YangStoreException, IOException {
-        byteArrayInputStreams = new ArrayList<>();
-        for (InputStream inputStream : inputStreams) {
-            assertNotNull(inputStream);
-            byte[] content = IOUtils.toByteArray(inputStream);
-            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
-                    content);
-            byteArrayInputStreams.add(byteArrayInputStream);
-        }
-    }
-
-    @Override
-    public YangStoreSnapshot getYangStoreSnapshot() throws YangStoreException {
-        for (InputStream inputStream : byteArrayInputStreams) {
-            try {
-                inputStream.reset();
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        YangParserImpl yangParser = new YangParserImpl();
-        final SchemaContext schemaContext = yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(byteArrayInputStreams).values()));
-        YangStoreServiceImpl yangStoreService = new YangStoreServiceImpl(new SchemaContextProvider() {
-            @Override
-            public SchemaContext getSchemaContext() {
-                return schemaContext ;
-            }
-        });
-        return yangStoreService.getYangStoreSnapshot();
-    }
-}
index eb99be0dc08f006ece7f7a93193f103bfa2bfb61..4b49c0928b09864342519cd9b2b5770b032cba30 100644 (file)
@@ -11,7 +11,6 @@ import static junit.framework.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithName;
@@ -20,41 +19,32 @@ import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToDocu
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
 import java.io.IOException;
-import java.io.InputStream;
+import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
-import java.util.Collection;
+import java.net.SocketAddress;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import javax.management.InstanceNotFoundException;
 import javax.management.Notification;
 import javax.management.NotificationListener;
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
-import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
 import org.opendaylight.controller.netconf.mapping.api.Capability;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
 import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
@@ -65,64 +55,48 @@ import org.xml.sax.SAXException;
 
 public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
 
-    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
+    public static final int PORT = 12026;
+    private static final InetSocketAddress TCP_ADDRESS = new InetSocketAddress(LOOPBACK_ADDRESS, PORT);
 
-    private NetconfClientDispatcher clientDispatcher;
-    private DefaultCommitNotificationProducer commitNotifier;
+    private NetconfMonitoringServiceImpl netconfMonitoringService;
 
-    @Before
-    public void setUp() throws Exception {
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,NetconfITTest.FACTORIES));
-
-        NetconfMonitoringServiceImpl monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
-
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
-        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
-        factoriesListener
-                .onAddNetconfOperationServiceFactory(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
-                        new NetconfMonitoringOperationService(monitoringService)));
-
-
-        commitNotifier = new DefaultCommitNotificationProducer(platformMBeanServer);
-        NetconfServerDispatcher dispatch = createDispatcher(factoriesListener, mockSessionMonitoringService(), commitNotifier);
-        ChannelFuture s = dispatch.createServer(tcpAddress);
-        s.await();
-
-        clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
+    @Override
+    protected void setUpTestInitial() {
+        netconfMonitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
     }
 
-    @After
-    public void cleanUp(){
-        commitNotifier.close();
+    @Override
+    protected SessionMonitoringService getNetconfMonitoringService() throws Exception {
+        return netconfMonitoringService;
     }
 
-    private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
-        final Collection<InputStream> yangDependencies = NetconfITTest.getBasicYangs();
-        return new HardcodedYangStoreService(yangDependencies);
+    @Override
+    protected SocketAddress getTcpServerAddress() {
+        return TCP_ADDRESS;
     }
 
-
-    protected SessionMonitoringService mockSessionMonitoringService() {
-        SessionMonitoringService mockedSessionMonitor = mock(SessionMonitoringService.class);
-        doNothing().when(mockedSessionMonitor).onSessionUp(any(NetconfManagementSession.class));
-        doNothing().when(mockedSessionMonitor).onSessionDown(any(NetconfManagementSession.class));
-        return mockedSessionMonitor;
+    @Override
+    protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories() {
+        return Collections.<NetconfOperationServiceFactory>singletonList(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
+                new NetconfMonitoringOperationService(netconfMonitoringService)));
     }
 
-
+    @Override
+    protected DefaultCommitNotificationProducer getNotificationProducer() {
+        return new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
+    }
 
     @Test
     public void testNetconfCommitNotifications() throws Exception {
+        final VerifyingNotificationListener notificationVerifier = createCommitNotificationListener();
+        final VerifyingPersister mockedAggregator = mockAggregator();
 
-        VerifyingNotificationListener notificationVerifier = createCommitNotificationListener();
-        VerifyingPersister mockedAggregator = mockAggregator();
-
-        try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
+        try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 4000))) {
             try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(
                     platformMBeanServer, mockedAggregator)) {
 
 
-                try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
+                try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 4000))) {
                     NetconfMessage response = netconfClient.sendMessage(loadGetConfigMessage());
                     assertContainsElementWithName(response.getDocument(), "modules");
                     assertContainsElementWithName(response.getDocument(), "services");
@@ -152,7 +126,7 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
     }
 
     private VerifyingNotificationListener createCommitNotificationListener() throws InstanceNotFoundException {
-        VerifyingNotificationListener listener = new VerifyingNotificationListener();
+        final VerifyingNotificationListener listener = new VerifyingNotificationListener();
         platformMBeanServer.addNotificationListener(DefaultCommitNotificationProducer.OBJECT_NAME, listener, null, null);
         return listener;
     }
@@ -171,12 +145,12 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
 
 
     public NetconfOperationProvider getNetconfOperationProvider() {
-        NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
-        NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
-        NetconfOperationService service = mock(NetconfOperationService.class);
-        Set<Capability> caps = Sets.newHashSet();
+        final NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
+        final NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
+        final NetconfOperationService service = mock(NetconfOperationService.class);
+        final Set<Capability> caps = Sets.newHashSet();
         doReturn(caps).when(service).getCapabilities();
-        Set<NetconfOperationService> services = Sets.newHashSet(service);
+        final Set<NetconfOperationService> services = Sets.newHashSet(service);
         doReturn(services).when(snap).getServices();
         doReturn(snap).when(factoriesListener).openSnapshot(anyString());
 
@@ -187,23 +161,23 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
         public List<Notification> notifications = Lists.newArrayList();
 
         @Override
-        public void handleNotification(Notification notification, Object handback) {
+        public void handleNotification(final Notification notification, final Object handback) {
             this.notifications.add(notification);
         }
 
-        void assertNotificationCount(Object size) {
+        void assertNotificationCount(final Object size) {
             assertEquals(size, notifications.size());
         }
 
-        void assertNotificationContent(int notificationIndex, int expectedModulesSize, int expectedServicesSize, int expectedCapsSize) {
-            Notification notification = notifications.get(notificationIndex);
+        void assertNotificationContent(final int notificationIndex, final int expectedModulesSize, final int expectedServicesSize, final int expectedCapsSize) {
+            final Notification notification = notifications.get(notificationIndex);
             assertEquals(CommitJMXNotification.class, notification.getClass());
-            int capsSize = ((CommitJMXNotification) notification).getCapabilities().size();
+            final int capsSize = ((CommitJMXNotification) notification).getCapabilities().size();
             assertEquals("Expected capabilities count", expectedCapsSize, capsSize);
-            Element configSnapshot = ((CommitJMXNotification) notification).getConfigSnapshot();
-            int modulesSize = configSnapshot.getElementsByTagName("module").getLength();
+            final Element configSnapshot = ((CommitJMXNotification) notification).getConfigSnapshot();
+            final int modulesSize = configSnapshot.getElementsByTagName("module").getLength();
             assertEquals("Expected modules count", expectedModulesSize, modulesSize);
-            int servicesSize = configSnapshot.getElementsByTagName("instance").getLength();
+            final int servicesSize = configSnapshot.getElementsByTagName("instance").getLength();
             assertEquals("Expected services count", expectedServicesSize, servicesSize);
         }
     }
@@ -214,12 +188,12 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
         private Persister mockedPersister;
 
         public VerifyingPersister() throws IOException {
-            Persister mockedAggregator = mock(Persister.class);
+            final Persister mockedAggregator = mock(Persister.class);
 
             doAnswer(new Answer<Object>() {
                 @Override
-                public Object answer(InvocationOnMock invocation) throws Throwable {
-                    ConfigSnapshotHolder configSnapshot = (ConfigSnapshotHolder) invocation.getArguments()[0];
+                public Object answer(final InvocationOnMock invocation) throws Throwable {
+                    final ConfigSnapshotHolder configSnapshot = (ConfigSnapshotHolder) invocation.getArguments()[0];
                     snapshots.add(configSnapshot);
                     return null;
                 }
@@ -228,22 +202,22 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
             this.mockedPersister = mockedAggregator;
         }
 
-        void assertSnapshotCount(Object size) {
+        void assertSnapshotCount(final Object size) {
             assertEquals(size, snapshots.size());
         }
 
-        void assertSnapshotContent(int notificationIndex, int expectedModulesSize, int expectedServicesSize, int expectedCapsSize)
+        void assertSnapshotContent(final int notificationIndex, final int expectedModulesSize, final int expectedServicesSize, final int expectedCapsSize)
                 throws SAXException, IOException {
-            ConfigSnapshotHolder snapshot = snapshots.get(notificationIndex);
-            int capsSize = snapshot.getCapabilities().size();
+            final ConfigSnapshotHolder snapshot = snapshots.get(notificationIndex);
+            final int capsSize = snapshot.getCapabilities().size();
             assertEquals("Expected capabilities count", expectedCapsSize, capsSize);
-            Document configSnapshot = readXmlToDocument(snapshot.getConfigSnapshot());
+            final Document configSnapshot = readXmlToDocument(snapshot.getConfigSnapshot());
             assertElementsCount(configSnapshot, "module", expectedModulesSize);
             assertElementsCount(configSnapshot, "instance", expectedServicesSize);
         }
 
         @Override
-        public void persistConfig(ConfigSnapshotHolder configSnapshotHolder) throws IOException {
+        public void persistConfig(final ConfigSnapshotHolder configSnapshotHolder) throws IOException {
             mockedPersister.persistConfig(configSnapshotHolder);
         }
 
diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITMonitoringTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITMonitoringTest.java
new file mode 100644 (file)
index 0000000..72a2f8f
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
+import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
+import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.w3c.dom.Document;
+
+public class NetconfITMonitoringTest extends AbstractNetconfConfigTest {
+
+    public static final int PORT = 12025;
+    public static final InetSocketAddress TCP_ADDRESS = new InetSocketAddress(LOOPBACK_ADDRESS, PORT);
+    public static final TestingCapability TESTING_CAPABILITY = new TestingCapability();
+
+    private NetconfMonitoringServiceImpl netconfMonitoringService;
+
+    @Override
+    protected void setUpTestInitial() {
+        netconfMonitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
+    }
+
+    @Override
+    protected SessionMonitoringService getNetconfMonitoringService() throws Exception {
+        return netconfMonitoringService;
+    }
+
+    @Override
+    protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories() {
+        return Collections.<NetconfOperationServiceFactory>singletonList(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
+                new NetconfMonitoringOperationService(netconfMonitoringService)));
+    }
+
+    @Override
+    protected InetSocketAddress getTcpServerAddress() {
+        return TCP_ADDRESS;
+    }
+
+    static SessionMonitoringService getNetconfMonitoringListenerService(final Logger logger, final NetconfMonitoringServiceImpl monitor) {
+        return new SessionMonitoringService() {
+            @Override
+            public void onSessionUp(final NetconfManagementSession session) {
+                logger.debug("Management session up {}", session);
+                monitor.onSessionUp(session);
+            }
+
+            @Override
+            public void onSessionDown(final NetconfManagementSession session) {
+                logger.debug("Management session down {}", session);
+                monitor.onSessionDown(session);
+            }
+        };
+    }
+
+    @Test
+    public void testGetResponseFromMonitoring() throws Exception {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 10000))) {
+            try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("client-monitoring2", getClientDispatcher(), getClientConfiguration(TCP_ADDRESS, 10000))) {
+                Thread.sleep(500);
+                final NetconfMessage response = netconfClient2.sendMessage(getGet());
+                assertSessionElementsInResponse(response.getDocument(), 2);
+            }
+            Thread.sleep(500);
+            final NetconfMessage response = netconfClient.sendMessage(getGet());
+            assertSessionElementsInResponse(response.getDocument(), 1);
+        }
+    }
+
+
+    @Test(timeout = 13 * 10000)
+    public void testClientHelloWithAuth() throws Exception {
+        String fileName = "netconfMessages/client_hello_with_auth.xml";
+        final String hello = XmlFileLoader.fileToString(fileName);
+
+        fileName = "netconfMessages/get.xml";
+        final String get = XmlFileLoader.fileToString(fileName);
+
+        final Socket sock = new Socket(TCP_ADDRESS.getHostName(), TCP_ADDRESS.getPort());
+        sock.getOutputStream().write(hello.getBytes(Charsets.UTF_8));
+        final String separator = "]]>]]>";
+
+        sock.getOutputStream().write(separator.getBytes(Charsets.UTF_8));
+        sock.getOutputStream().write(get.getBytes(Charsets.UTF_8));
+        sock.getOutputStream().write(separator.getBytes(Charsets.UTF_8));
+
+        final StringBuilder responseBuilder = new StringBuilder();
+
+        try (InputStream inputStream = sock.getInputStream();
+             InputStreamReader reader = new InputStreamReader(inputStream);
+             BufferedReader buff = new BufferedReader(reader)) {
+            String line;
+            while ((line = buff.readLine()) != null) {
+
+                responseBuilder.append(line);
+                responseBuilder.append(System.lineSeparator());
+
+                if(line.contains("</rpc-reply>"))
+                    break;
+            }
+        }
+
+        sock.close();
+
+        final String helloMsg = responseBuilder.substring(0, responseBuilder.indexOf(separator));
+        Document doc = XmlUtil.readXmlToDocument(helloMsg);
+        assertContainsElementWithText(doc, "urn:ietf:params:netconf:capability:candidate:1.0");
+
+        final String replyMsg = responseBuilder.substring(responseBuilder.indexOf(separator) + separator.length());
+        doc = XmlUtil.readXmlToDocument(replyMsg);
+        assertContainsElementWithText(doc, "tomas");
+    }
+
+    private void assertSessionElementsInResponse(final Document document, final int i) {
+        final int elementSize = document.getElementsByTagName("session-id").getLength();
+        assertEquals("Incorrect number of session-id tags in " + XmlUtil.toString(document), i, elementSize);
+    }
+
+    public static NetconfOperationProvider getNetconfOperationProvider() {
+        final NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
+        final NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
+        try {
+            doNothing().when(snap).close();
+        } catch (final Exception e) {
+            // not happening
+            throw new IllegalStateException(e);
+        }
+        final NetconfOperationService service = mock(NetconfOperationService.class);
+        final Set<Capability> caps = Sets.newHashSet();
+        caps.add(TESTING_CAPABILITY);
+
+        doReturn(caps).when(service).getCapabilities();
+        final Set<NetconfOperationService> services = Sets.newHashSet(service);
+        doReturn(services).when(snap).getServices();
+        doReturn(snap).when(factoriesListener).openSnapshot(anyString());
+
+        return factoriesListener;
+    }
+
+    private static class TestingCapability implements Capability {
+        @Override
+        public String getCapabilityUri() {
+            return "namespaceModuleRevision";
+        }
+
+        @Override
+        public Optional<String> getModuleNamespace() {
+            return Optional.of("namespace");
+        }
+
+        @Override
+        public Optional<String> getModuleName() {
+            return Optional.of("name");
+        }
+
+        @Override
+        public Optional<String> getRevision() {
+            return Optional.of("revision");
+        }
+
+        @Override
+        public Optional<String> getCapabilitySchema() {
+            return Optional.of("content");
+        }
+
+        @Override
+        public Optional<List<String>> getLocation() {
+            return Optional.absent();
+        }
+    }
+}
index e5e34548b3a4e7b4f0d6049920cb9cde56a3a25d..67ccf0c02ca4a2531986000bfc66db5bddce29f4 100644 (file)
@@ -8,27 +8,25 @@
 
 package org.opendaylight.controller.netconf.it;
 
-import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
+import com.google.common.collect.Lists;
+import io.netty.channel.local.LocalAddress;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
-import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
-
-import junit.framework.Assert;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.auth.AuthProvider;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
@@ -37,87 +35,44 @@ import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionList
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
 import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
-import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
 
-import com.google.common.collect.Lists;
-
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GenericFutureListener;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
 public class NetconfITSecureTest extends AbstractNetconfConfigTest {
 
-    private static final InetSocketAddress tlsAddress = new InetSocketAddress("127.0.0.1", 12024);
+    public static final int PORT = 12024;
+    private static final InetSocketAddress TLS_ADDRESS = new InetSocketAddress("127.0.0.1", PORT);
+
+    public static final String USERNAME = "user";
+    public static final String PASSWORD = "pwd";
 
-    private DefaultCommitNotificationProducer commitNot;
     private NetconfSSHServer sshServer;
-    private NetconfMessage getConfig;
 
     @Before
     public void setUp() throws Exception {
-        this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
-
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, getModuleFactories().toArray(
-                new ModuleFactory[0])));
-
-        final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
-        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
-
-        commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
-
-
-        final NetconfServerDispatcher dispatchS = createDispatcher(factoriesListener);
-        ChannelFuture s = dispatchS.createLocalServer(NetconfConfigUtil.getNetconfLocalAddress());
-        s.await();
-        EventLoopGroup bossGroup  = new NioEventLoopGroup();
-
         final char[] pem = PEMGenerator.generate().toCharArray();
-        sshServer = NetconfSSHServer.start(tlsAddress.getPort(), NetconfConfigUtil.getNetconfLocalAddress(), bossGroup, pem);
+        sshServer = NetconfSSHServer.start(TLS_ADDRESS.getPort(), NetconfConfigUtil.getNetconfLocalAddress(), getNettyThreadgroup(), pem);
         sshServer.setAuthProvider(getAuthProvider());
     }
 
-    private NetconfServerDispatcher createDispatcher(final NetconfOperationServiceFactoryListenerImpl factoriesListener) {
-        return super.createDispatcher(factoriesListener, NetconfITTest.getNetconfMonitoringListenerService(), commitNot);
-    }
-
     @After
     public void tearDown() throws Exception {
         sshServer.close();
-        commitNot.close();
         sshServer.join();
     }
 
-    private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
-        final Collection<InputStream> yangDependencies = NetconfITTest.getBasicYangs();
-        return new HardcodedYangStoreService(yangDependencies);
-    }
-
-    protected List<ModuleFactory> getModuleFactories() {
-        return asList(NetconfITTest.FACTORIES);
-    }
-
     @Test
     public void testSecure() throws Exception {
         final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
         try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration())) {
-            NetconfMessage response = netconfClient.sendMessage(getConfig);
-            Assert.assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
+            NetconfMessage response = netconfClient.sendMessage(getGetConfig());
+            assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
                     NetconfMessageUtil.isErrorMessage(response));
 
             final NetconfMessage gs = new NetconfMessage(XmlUtil.readXmlToDocument("<rpc message-id=\"2\"\n" +
@@ -128,7 +83,7 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
                     "</rpc>\n"));
 
             response = netconfClient.sendMessage(gs);
-            Assert.assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
+            assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
                     NetconfMessageUtil.isErrorMessage(response));
         }
     }
@@ -146,7 +101,7 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
 
             final int requests = 1000;
             for (int i = 0; i < requests; i++) {
-                final Future<NetconfMessage> netconfMessageFuture = netconfClient.sendRequest(getConfig);
+                final Future<NetconfMessage> netconfMessageFuture = netconfClient.sendRequest(getGetConfig());
                 futures.add(netconfMessageFuture);
                 netconfMessageFuture.addListener(new GenericFutureListener<Future<? super NetconfMessage>>() {
                     @Override
@@ -164,13 +119,13 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
             // Give future listeners some time to finish counter incrementation
             Thread.sleep(5000);
 
-            org.junit.Assert.assertEquals(requests, responseCounter.get());
+            assertEquals(requests, responseCounter.get());
         }
     }
 
     public NetconfClientConfiguration getClientConfiguration() throws IOException {
         final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
-        b.withAddress(tlsAddress);
+        b.withAddress(TLS_ADDRESS);
         b.withSessionListener(new SimpleNetconfClientSessionListener());
         b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000));
         b.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH);
@@ -180,12 +135,18 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
     }
 
     public AuthProvider getAuthProvider() throws Exception {
-        AuthProvider mock = mock(AuthProvider.class);
-        doReturn(true).when(mock).authenticated(anyString(), anyString());
-        return mock;
+        final AuthProvider mockAuth = mock(AuthProvider.class);
+        doReturn("mockedAuth").when(mockAuth).toString();
+        doReturn(true).when(mockAuth).authenticated(anyString(), anyString());
+        return mockAuth;
     }
 
     public AuthenticationHandler getAuthHandler() throws IOException {
-        return new LoginPassword("user", "pwd");
+        return new LoginPassword(USERNAME, PASSWORD);
+    }
+
+    @Override
+    protected LocalAddress getTcpServerAddress() {
+        return NetconfConfigUtil.getNetconfLocalAddress();
     }
 }
index 8e69e6a345ffef868c2ed4e5bc454c440dc989a4..a7a9d7494af73e8553bf9ce9a638b02958c5ece0 100644 (file)
@@ -8,11 +8,11 @@
 
 package org.opendaylight.controller.netconf.it;
 
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
@@ -20,15 +20,8 @@ import com.google.common.base.Function;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
 import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -36,35 +29,19 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 import javax.management.ObjectName;
 import javax.xml.parsers.ParserConfigurationException;
-import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
-import org.junit.matchers.JUnitMatchers;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
-import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleMXBean;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
-import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -80,129 +57,57 @@ import org.xml.sax.SAXException;
 
 public class NetconfITTest extends AbstractNetconfConfigTest {
 
-    // TODO refactor, pull common code up to AbstractNetconfITTest
+    public static final int PORT = 12023;
+    public static final InetSocketAddress TCP_ADDRESS = new InetSocketAddress(LOOPBACK_ADDRESS, PORT);
 
-    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
-
-
-    private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
-    private DefaultCommitNotificationProducer commitNotificationProducer;
-    private NetconfServerDispatcher dispatch;
-
-    private NetconfClientDispatcherImpl clientDispatcher;
-
-    static ModuleFactory[] FACTORIES = {new TestImplModuleFactory(), new DepTestImplModuleFactory(),
-            new NetconfTestImplModuleFactory(), new IdentityTestModuleFactory(),
-            new MultipleDependenciesModuleFactory()};
+    private NetconfMessage getConfigCandidate, editConfig, closeSession;
+    private NetconfClientDispatcher clientDispatcher;
 
     @Before
     public void setUp() throws Exception {
-        initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,
-                FACTORIES
-        ));
-
         loadMessages();
-
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
-        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
-
-        commitNotificationProducer = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
-
-        dispatch = createDispatcher(factoriesListener);
-        ChannelFuture s = dispatch.createServer(tcpAddress);
-        s.await();
-
-        clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
-    }
-
-    private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
-        return super.createDispatcher(factoriesListener, getNetconfMonitoringListenerService(), commitNotificationProducer);
+        clientDispatcher = getClientDispatcher();
     }
 
-    static NetconfMonitoringServiceImpl getNetconfMonitoringListenerService() {
-        NetconfOperationProvider netconfOperationProvider = mock(NetconfOperationProvider.class);
-        NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
-        doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
-        doReturn(snap).when(netconfOperationProvider).openSnapshot(anyString());
-        return new NetconfMonitoringServiceImpl(netconfOperationProvider);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        commitNotificationProducer.close();
-        clientDispatcher.close();
+    @Override
+    protected InetSocketAddress getTcpServerAddress() {
+        return TCP_ADDRESS;
     }
 
     private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
         this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml");
-        this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
         this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml");
         this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml");
     }
 
-    private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
-        final Collection<InputStream> yangDependencies = getBasicYangs();
-        return new HardcodedYangStoreService(yangDependencies);
-    }
-
-    static Collection<InputStream> getBasicYangs() throws IOException {
-
-        List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
-                "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang", "/META-INF/yang/test-types.yang",
-                "/META-INF/yang/ietf-inet-types.yang");
-        final Collection<InputStream> yangDependencies = new ArrayList<>();
-        List<String> failedToFind = new ArrayList<>();
-        for (String path : paths) {
-            InputStream resourceAsStream = NetconfITTest.class.getResourceAsStream(path);
-            if (resourceAsStream == null) {
-                failedToFind.add(path);
-            } else {
-                yangDependencies.add(resourceAsStream);
-            }
-        }
-        assertEquals("Some yang files were not found", Collections.<String>emptyList(), failedToFind);
-        return yangDependencies;
-    }
-
-
     @Test
     public void testNetconfClientDemonstration() throws Exception {
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", clientDispatcher, getClientConfiguration(TCP_ADDRESS, 4000))) {
 
-            Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
-            long sessionId = netconfClient.getSessionId();
+            final Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
+            final long sessionId = netconfClient.getSessionId();
 
             // NetconfMessage can be created :
             // new NetconfMessage(XmlUtil.readXmlToDocument("<xml/>"));
 
-            NetconfMessage response = netconfClient.sendMessage(getConfig);
+            final NetconfMessage response = netconfClient.sendMessage(getGetConfig());
             response.getDocument();
         }
     }
 
     @Test
     public void testTwoSessions() throws Exception {
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", clientDispatcher, getClientConfiguration(tcpAddress, 10000)))  {
-            try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", clientDispatcher, getClientConfiguration(TCP_ADDRESS, 10000)))  {
+            try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", clientDispatcher, getClientConfiguration(TCP_ADDRESS, 10000))) {
                 assertNotNull(netconfClient2.getCapabilities());
             }
         }
     }
 
-    @Ignore
-    @Test
-    public void waitingTest() throws Exception {
-        final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
-        transaction.createModule(DepTestImplModuleFactory.NAME, "eb");
-        transaction.commit();
-        Thread.currentThread().suspend();
-    }
-
     @Test
     public void rpcReplyContainsAllAttributesTest() throws Exception {
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
-            final String rpc = "<rpc message-id=\"5\" a=\"a\" b=\"44\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
-                    + "<get/>" + "</rpc>";
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
+            final String rpc = "<rpc message-id=\"5\" a=\"a\" b=\"44\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><get/>" + "</rpc>";
             final Document doc = XmlUtil.readXmlToDocument(rpc);
             final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
             assertNotNull(message);
@@ -228,9 +133,8 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void rpcReplyErrorContainsAllAttributesTest() throws Exception {
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
-            final String rpc = "<rpc message-id=\"1\" a=\"adada\" b=\"4\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
-                    + "<commit/>" + "</rpc>";
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
+            final String rpc = "<rpc message-id=\"1\" a=\"adada\" b=\"4\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><commit/>" + "</rpc>";
             final Document doc = XmlUtil.readXmlToDocument(rpc);
             final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
             final NamedNodeMap expectedAttributes = doc.getDocumentElement().getAttributes();
@@ -243,16 +147,16 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     @Test
     public void rpcOutputContainsCorrectNamespace() throws Exception {
         final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
-        ObjectName dep = transaction.createModule(DepTestImplModuleFactory.NAME, "instanceD");
-        ObjectName impl = transaction.createModule(NetconfTestImplModuleFactory.NAME, "instance");
-        NetconfTestImplModuleMXBean proxy = configRegistryClient
+        final ObjectName dep = transaction.createModule(DepTestImplModuleFactory.NAME, "instanceD");
+        final ObjectName impl = transaction.createModule(NetconfTestImplModuleFactory.NAME, "instance");
+        final NetconfTestImplModuleMXBean proxy = configRegistryClient
                 .newMXBeanProxy(impl, NetconfTestImplModuleMXBean.class);
         proxy.setTestingDep(dep);
         proxy.setSimpleShort((short) 0);
 
         transaction.commit();
 
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
             final String expectedNamespace = "urn:opendaylight:params:xml:ns:yang:controller:test:impl";
 
             final String rpc = "<rpc message-id=\"5\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
@@ -275,7 +179,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testCloseSession() throws Exception {
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
 
             // edit config
             Document rpcReply = netconfClient.sendMessage(this.editConfig)
@@ -291,7 +195,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testEditConfig() throws Exception {
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
             // send edit_config.xml
             final Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
             assertIsOK(rpcReply);
@@ -300,7 +204,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testValidate() throws Exception {
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
             // begin transaction
             Document rpcReply = netconfClient.sendMessage(getConfigCandidate).getDocument();
             assertEquals("data", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
@@ -318,7 +222,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     }
 
     private Document assertGetConfigWorks(final TestingNetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException, NetconfDocumentedException {
-        return assertGetConfigWorks(netconfClient, this.getConfig);
+        return assertGetConfigWorks(netconfClient, getGetConfig());
     }
 
     private Document assertGetConfigWorks(final TestingNetconfClient netconfClient, final NetconfMessage getConfigMessage)
@@ -331,14 +235,14 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testGetConfig() throws Exception {
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
             assertGetConfigWorks(netconfClient);
         }
     }
 
     @Test
     public void createYangTestBasedOnYuma() throws Exception {
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
             Document rpcReply = netconfClient.sendMessage(
                     XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_yang-test.xml"))
                     .getDocument();
@@ -351,7 +255,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
             final ObjectName on = new ObjectName(
                     "org.opendaylight.controller:instanceName=impl-dep-instance,type=Module,moduleFactoryName=impl-dep");
-            Set<ObjectName> cfgBeans = configRegistryClient.lookupConfigBeans();
+            final Set<ObjectName> cfgBeans = configRegistryClient.lookupConfigBeans();
             assertEquals(cfgBeans, Sets.newHashSet(on));
         }
     }
@@ -364,21 +268,21 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
     @Test
     public void testIdRef() throws Exception {
-        NetconfMessage editId = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
-        NetconfMessage commit = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml");
+        final NetconfMessage editId = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
+        final NetconfMessage commit = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml");
 
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
             assertIsOK(netconfClient.sendMessage(editId).getDocument());
             assertIsOK(netconfClient.sendMessage(commit).getDocument());
 
-            NetconfMessage response = netconfClient.sendMessage(getConfig);
+            final NetconfMessage response = netconfClient.sendMessage(getGetConfig());
 
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>"));
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>"));
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>"));
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>"));
 
-        } catch (Exception e) {
+        } catch (final Exception e) {
             fail(Throwables.getStackTraceAsString(e));
         }
     }
@@ -394,25 +298,24 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         return ret;
     }
 
-
     @Test
     public void testMultipleDependencies() throws Exception {
         // push first xml, should add parent and d1,d2 dependencies
-        try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
-            Document rpcReply = netconfClient.sendMessage(
+        try (TestingNetconfClient netconfClient = createSession(TCP_ADDRESS, "1")) {
+            final Document rpcReply = netconfClient.sendMessage(
                     XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps1.xml"))
                     .getDocument();
             assertIsOK(rpcReply);
             commit(netconfClient);
         }
         // verify that parent.getTestingDeps == d1,d2
-        MultipleDependenciesModuleMXBean parentProxy = configRegistryClient.newMXBeanProxy(
+        final MultipleDependenciesModuleMXBean parentProxy = configRegistryClient.newMXBeanProxy(
                 configRegistryClient.lookupConfigBean(MultipleDependenciesModuleFactory.NAME, "parent"),
                 MultipleDependenciesModuleMXBean.class);
         {
-            List<ObjectName> testingDeps = parentProxy.getTestingDeps();
+            final List<ObjectName> testingDeps = parentProxy.getTestingDeps();
             assertEquals(2, testingDeps.size());
-            Set<String> actualRefs = getServiceReferences(testingDeps);
+            final Set<String> actualRefs = getServiceReferences(testingDeps);
             assertEquals(Sets.newHashSet("ref_d1", "ref_d2"), actualRefs);
         }
 
@@ -422,35 +325,35 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         mergeD3(parentProxy);
     }
 
-    public void mergeD3(MultipleDependenciesModuleMXBean parentProxy) throws Exception {
+    public void mergeD3(final MultipleDependenciesModuleMXBean parentProxy) throws Exception {
         try (TestingNetconfClient netconfClient = new TestingNetconfClient(
-                "test " + tcpAddress.toString(), clientDispatcher, getClientConfiguration(tcpAddress, 5000))) {
+                "test " + TCP_ADDRESS.toString(), clientDispatcher, getClientConfiguration(TCP_ADDRESS, 5000))) {
 
-            Document rpcReply = netconfClient.sendMessage(
+            final Document rpcReply = netconfClient.sendMessage(
                     XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_multiple-deps2.xml"))
                     .getDocument();
             assertIsOK(rpcReply);
             commit(netconfClient);
         }
         {
-            List<ObjectName> testingDeps = parentProxy.getTestingDeps();
+            final List<ObjectName> testingDeps = parentProxy.getTestingDeps();
             assertEquals(3, testingDeps.size());
-            Set<String> actualRefs = getServiceReferences(testingDeps);
+            final Set<String> actualRefs = getServiceReferences(testingDeps);
             assertEquals(Sets.newHashSet("ref_d1", "ref_d2", "ref_d3"), actualRefs);
         }
     }
 
-    public Set<String> getServiceReferences(List<ObjectName> testingDeps) {
+    public Set<String> getServiceReferences(final List<ObjectName> testingDeps) {
         return new HashSet<>(Lists.transform(testingDeps, new Function<ObjectName, String>() {
             @Override
-            public String apply(ObjectName input) {
+            public String apply(final ObjectName input) {
                 return ObjectNameUtil.getReferenceName(input);
             }
         }));
     }
 
-    public void commit(TestingNetconfClient netconfClient) throws Exception {
-        Document rpcReply;
+    public void commit(final TestingNetconfClient netconfClient) throws Exception {
+        final Document rpcReply;
         rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml"))
                 .getDocument();
         assertIsOK(rpcReply);
diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfMonitoringITTest.java
deleted file mode 100644 (file)
index 05e3257..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.it;
-
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import io.netty.channel.ChannelFuture;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
-import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
-import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
-import org.opendaylight.controller.netconf.mapping.api.Capability;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
-import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
-import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
-import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-
-public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
-
-    private static final Logger logger =  LoggerFactory.getLogger(NetconfITTest.class);
-
-    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
-
-    @Mock
-    private DefaultCommitNotificationProducer commitNot;
-    private NetconfServerDispatcher dispatch;
-
-    private NetconfClientDispatcherImpl clientDispatcher;
-
-    private NetconfMonitoringServiceImpl monitoringService;
-
-    @Before
-    public void setUp() throws Exception {
-        super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, NetconfITTest.FACTORIES));
-
-        monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
-
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
-        factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
-        factoriesListener
-                .onAddNetconfOperationServiceFactory(new NetconfMonitoringActivator.NetconfMonitoringOperationServiceFactory(
-                        new NetconfMonitoringOperationService(monitoringService)));
-
-
-        dispatch = createDispatcher(factoriesListener);
-        ChannelFuture s = dispatch.createServer(tcpAddress);
-        s.await();
-
-        clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
-    }
-
-    private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
-        final Collection<InputStream> yangDependencies = NetconfITTest.getBasicYangs();
-        return new HardcodedYangStoreService(yangDependencies);
-    }
-
-    private NetconfServerDispatcher createDispatcher(
-                                                     NetconfOperationServiceFactoryListenerImpl factoriesListener) {
-        return super.createDispatcher(factoriesListener, getNetconfMonitoringListenerService(logger, monitoringService), commitNot);
-    }
-
-    static SessionMonitoringService getNetconfMonitoringListenerService(final Logger logger, final NetconfMonitoringServiceImpl monitor) {
-        return new SessionMonitoringService() {
-            @Override
-            public void onSessionUp(NetconfManagementSession session) {
-                logger.debug("Management session up {}", session);
-                monitor.onSessionUp(session);
-            }
-
-            @Override
-            public void onSessionDown(NetconfManagementSession session) {
-                logger.debug("Management session down {}", session);
-                monitor.onSessionDown(session);
-            }
-        };
-    }
-
-
-    @Test
-    public void testGetResponseFromMonitoring() throws Exception {
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
-        try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("client-monitoring2", clientDispatcher, getClientConfiguration(tcpAddress, 4000))) {
-            NetconfMessage response = netconfClient.sendMessage(loadGetMessage());
-            assertSessionElementsInResponse(response.getDocument(), 2);
-        }
-            NetconfMessage response = netconfClient.sendMessage(loadGetMessage());
-            assertSessionElementsInResponse(response.getDocument(), 1);
-        }
-    }
-
-
-    @Test(timeout = 13 * 10000)
-    public void testClientHelloWithAuth() throws Exception {
-        String fileName = "netconfMessages/client_hello_with_auth.xml";
-        String hello = XmlFileLoader.fileToString(fileName);
-
-        fileName = "netconfMessages/get.xml";
-        String get = XmlFileLoader.fileToString(fileName);
-
-        Socket sock = new Socket(tcpAddress.getHostName(), tcpAddress.getPort());
-        sock.getOutputStream().write(hello.getBytes(Charsets.UTF_8));
-        String separator = "]]>]]>";
-
-        sock.getOutputStream().write(separator.getBytes(Charsets.UTF_8));
-        sock.getOutputStream().write(get.getBytes(Charsets.UTF_8));
-        sock.getOutputStream().write(separator.getBytes(Charsets.UTF_8));
-
-        StringBuilder responseBuilder = new StringBuilder();
-
-        try (InputStream inputStream = sock.getInputStream();
-             InputStreamReader reader = new InputStreamReader(inputStream);
-             BufferedReader buff = new BufferedReader(reader)) {
-            String line;
-            while ((line = buff.readLine()) != null) {
-
-                responseBuilder.append(line);
-                responseBuilder.append(System.lineSeparator());
-
-                if(line.contains("</rpc-reply>"))
-                    break;
-            }
-        }
-
-        sock.close();
-
-        String helloMsg = responseBuilder.substring(0, responseBuilder.indexOf(separator));
-        Document doc = XmlUtil.readXmlToDocument(helloMsg);
-        assertContainsElementWithText(doc, "urn:ietf:params:netconf:capability:candidate:1.0");
-
-        String replyMsg = responseBuilder.substring(responseBuilder.indexOf(separator) + separator.length());
-        doc = XmlUtil.readXmlToDocument(replyMsg);
-        assertContainsElementWithText(doc, "tomas");
-    }
-
-    private void assertSessionElementsInResponse(Document document, int i) {
-        int elementSize = document.getElementsByTagName("session-id").getLength();
-        Assert.assertEquals("Incorrect number of session-id tags in " + XmlUtil.toString(document),i, elementSize);
-    }
-
-    private NetconfMessage loadGetMessage() throws Exception {
-        return XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/get.xml");
-    }
-
-    public static NetconfOperationProvider getNetconfOperationProvider() throws Exception {
-        NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
-        NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
-        doNothing().when(snap).close();
-        NetconfOperationService service = mock(NetconfOperationService.class);
-        Set<Capability> caps = Sets.newHashSet();
-        caps.add(new Capability() {
-            @Override
-            public String getCapabilityUri() {
-                return "namespaceModuleRevision";
-            }
-
-            @Override
-            public Optional<String> getModuleNamespace() {
-                return Optional.of("namespace");
-            }
-
-            @Override
-            public Optional<String> getModuleName() {
-                return Optional.of("name");
-            }
-
-            @Override
-            public Optional<String> getRevision() {
-                return Optional.of("revision");
-            }
-
-            @Override
-            public Optional<String> getCapabilitySchema() {
-                return Optional.of("content");
-            }
-
-            @Override
-            public Optional<List<String>> getLocation() {
-                return Optional.absent();
-            }
-        });
-
-        doReturn(caps).when(service).getCapabilities();
-        Set<NetconfOperationService> services = Sets.newHashSet(service);
-        doReturn(services).when(snap).getServices();
-        doReturn(snap).when(factoriesListener).openSnapshot(anyString());
-
-        return factoriesListener;
-    }
-
-
-}
index 4d232a619a49affd154c46d9fd6aa92ec08592b6..f76bf4f4c37ebf96c99ba0eeccc90c9280f773da 100644 (file)
@@ -24,8 +24,7 @@ import com.google.common.base.Preconditions;
 
 public final class SSLUtil {
 
-    private SSLUtil() {
-    }
+    private SSLUtil() {}
 
     public static SSLContext initializeSecureContext(final String pass, final InputStream ksKeysFile, final InputStream ksTrustFile,
                                                      final String algorithm) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
index 35f2345248f1ac30203d014e78e5283e8c66f82b..4721acf209055190d30b12c73b1d7e80898b953c 100644 (file)
@@ -8,29 +8,13 @@
 
 package org.opendaylight.controller.netconf.test.tool;
 
-import java.io.File;
-import java.io.IOException;
-import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
-import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
+import org.opendaylight.controller.netconf.auth.AuthProvider;
 
 class AcceptingAuthProvider implements AuthProvider {
-    private final String privateKeyPEMString;
-
-    public AcceptingAuthProvider() {
-        try {
-            this.privateKeyPEMString = PEMGenerator.readOrGeneratePK(new File("PK"));
-        } catch (final IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
 
     @Override
     public synchronized boolean authenticated(final String username, final String password) {
         return true;
     }
 
-    @Override
-    public char[] getPEMAsCharArray() {
-        return privateKeyPEMString.toCharArray();
-    }
 }
index 3a52f0a85ea4af1aca3f3fb452bf1e711a2da2df..2cd5b19bd12a4c44a222a43acd8004df82debef1 100644 (file)
@@ -23,6 +23,7 @@ import io.netty.channel.local.LocalAddress;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
 import java.io.Closeable;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.lang.management.ManagementFactory;
@@ -55,6 +56,7 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
 import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
@@ -165,7 +167,8 @@ public class NetconfDeviceSimulator implements Closeable {
 
                 server = dispatcher.createLocalServer(tcpLocalAddress);
                 try {
-                    NetconfSSHServer.start(currentPort, tcpLocalAddress, new AcceptingAuthProvider(), nettyThreadgroup);
+                    final NetconfSSHServer sshServer = NetconfSSHServer.start(currentPort, tcpLocalAddress, nettyThreadgroup, getPemArray());
+                    sshServer.setAuthProvider(new AcceptingAuthProvider());
                 } catch (final Exception e) {
                     LOG.warn("Cannot start simulated device on {}, skipping", address, e);
                     // Close local server and continue
@@ -219,6 +222,14 @@ public class NetconfDeviceSimulator implements Closeable {
         return openDevices;
     }
 
+    private char[] getPemArray() {
+        try {
+            return PEMGenerator.readOrGeneratePK(new File("PK")).toCharArray();
+        } catch (final IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private Map<ModuleBuilder, String> parseSchemasToModuleBuilders(final Main.Params params) {
         final SharedSchemaRepository consumer = new SharedSchemaRepository("netconf-simulator");
         consumer.registerSchemaSourceListener(TextToASTTransformer.create(consumer, consumer));
index e2df13b9aa859d739114b72b89cb1072e891bd9f..c7ae4eb1726e33d82213f5bced6064eb68a79a52 100644 (file)
@@ -59,6 +59,10 @@ public class NeutronRouter_Interface implements Serializable {
         this.portUUID = portUUID;
     }
 
+    public String getID() {
+        return id;
+    }
+
     public void setID(String id) {
         this.id = id;
     }
index 5854d5577fe007be058adc5db033c4746d220dc3..d39241757fea07732c7920340fd3fdd5ebf37c7d 100644 (file)
@@ -81,7 +81,7 @@
           <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal</artifactId>
-            <version>0.7.1-SNAPSHOT</version>
+            <version>${sal.version}</version>
           </dependency>
         </dependencies>
       </plugin>